From 215ea62c6a7e432cc92db0648c5b26285c6c72c0 Mon Sep 17 00:00:00 2001 From: JerryShih Date: Sat, 24 Sep 2016 01:40:00 +0200 Subject: [PATCH 001/102] Bug 1160157 - skip content painting when the device is in device-reset/remove status. r=dvander --- gfx/layers/client/ClientLayerManager.cpp | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/gfx/layers/client/ClientLayerManager.cpp b/gfx/layers/client/ClientLayerManager.cpp index f7a875067fb3..74dfbf81cc30 100644 --- a/gfx/layers/client/ClientLayerManager.cpp +++ b/gfx/layers/client/ClientLayerManager.cpp @@ -304,12 +304,17 @@ ClientLayerManager::EndTransactionInternal(DrawPaintedLayerCallback aCallback, GetRoot()->ComputeEffectiveTransforms(Matrix4x4()); - if (gfxPrefs::AlwaysPaint() && XRE_IsContentProcess()) { - TimeStamp start = TimeStamp::Now(); - root->RenderLayer(); - mLastPaintTime = TimeStamp::Now() - start; + // Skip the painting if the device is in device-reset status. + if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) { + if (gfxPrefs::AlwaysPaint() && XRE_IsContentProcess()) { + TimeStamp start = TimeStamp::Now(); + root->RenderLayer(); + mLastPaintTime = TimeStamp::Now() - start; + } else { + root->RenderLayer(); + } } else { - root->RenderLayer(); + gfxCriticalNote << "LayerManager::EndTransaction skip RenderLayer()."; } if (!mRepeatTransaction && !GetRoot()->GetInvalidRegion().IsEmpty()) { @@ -626,8 +631,12 @@ ClientLayerManager::ForwardTransaction(bool aScheduleComposite) { TimeStamp start = TimeStamp::Now(); - if (mForwarder->GetSyncObject()) { - mForwarder->GetSyncObject()->FinalizeFrame(); + // Skip the synchronization for buffer since we also skip the painting during + // device-reset status. + if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) { + if (mForwarder->GetSyncObject()) { + mForwarder->GetSyncObject()->FinalizeFrame(); + } } mPhase = PHASE_FORWARD; From 6781bead2d51bcc967fd2ec60ac4069b3760c24f Mon Sep 17 00:00:00 2001 From: JerryShih Date: Sat, 24 Sep 2016 01:40:00 +0200 Subject: [PATCH 002/102] Bug 1160157 - remove the painting aborting for ClientPaintedLayer in device-remove/reset status. r=dvander Since we already have the device-remove checking in ClientLayerManager, this checking is redundant. --- gfx/layers/client/ClientPaintedLayer.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/gfx/layers/client/ClientPaintedLayer.cpp b/gfx/layers/client/ClientPaintedLayer.cpp index 70a568eefb79..871f10559b50 100644 --- a/gfx/layers/client/ClientPaintedLayer.cpp +++ b/gfx/layers/client/ClientPaintedLayer.cpp @@ -24,10 +24,6 @@ #include "gfx2DGlue.h" #include "ReadbackProcessor.h" -#ifdef XP_WIN -#include "gfxWindowsPlatform.h" -#endif - namespace mozilla { namespace layers { @@ -36,13 +32,6 @@ using namespace mozilla::gfx; void ClientPaintedLayer::PaintThebes() { -#ifdef XP_WIN - if (gfxWindowsPlatform::GetPlatform()->DidRenderingDeviceReset()) { - // If our rendering device has reset simply avoid rendering completely. - return; - } -#endif - PROFILER_LABEL("ClientPaintedLayer", "PaintThebes", js::ProfileEntry::Category::GRAPHICS); From ab9e34053dd5e02db8f9873bed70862cc2bec987 Mon Sep 17 00:00:00 2001 From: Tracy Walker Date: Mon, 26 Sep 2016 08:13:38 -0500 Subject: [PATCH 003/102] Bug 1279087 - In caps/tests/mochitests/bug995943.xul, widen range of assertion check for OSX 10.10 to 5-9 to reduce intermittent test timeouts. r=emk --- caps/tests/mochitest/test_bug995943.xul | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/caps/tests/mochitest/test_bug995943.xul b/caps/tests/mochitest/test_bug995943.xul index da2c1ae6e89d..3d3f06bd97b2 100644 --- a/caps/tests/mochitest/test_bug995943.xul +++ b/caps/tests/mochitest/test_bug995943.xul @@ -27,7 +27,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=995943 SimpleTest.waitForExplicitFinish(); SimpleTest.requestCompleteLog(); if (navigator.userAgent.indexOf("Mac OS X 10.10") != -1) - SimpleTest.expectAssertions(6, 9); // See bug 1067022 + SimpleTest.expectAssertions(5, 9); // See bug 1067022 else if (Services.appinfo.OS == "WINNT") SimpleTest.expectAssertions(0, 1); // See bug 1067022 From c0462c28b658370d8e9d5b91839b93d2c610b159 Mon Sep 17 00:00:00 2001 From: Jan Varga Date: Wed, 24 Aug 2016 13:40:25 +0800 Subject: [PATCH 004/102] Bug 1290853 - Iterate the blocked transactions in the first-come, first-served order. r=btseng --- dom/indexedDB/ActorsParent.cpp | 87 +++++++++++++------ .../transaction-lifetime-empty.html.ini | 3 - 2 files changed, 61 insertions(+), 29 deletions(-) delete mode 100644 testing/web-platform/meta/IndexedDB/transaction-lifetime-empty.html.ini diff --git a/dom/indexedDB/ActorsParent.cpp b/dom/indexedDB/ActorsParent.cpp index ed0b660e28f0..8ed1dd4c454f 100644 --- a/dom/indexedDB/ActorsParent.cpp +++ b/dom/indexedDB/ActorsParent.cpp @@ -5314,7 +5314,7 @@ private: struct IdleThreadInfo; struct ThreadInfo; class ThreadRunnable; - struct TransactionInfo; + class TransactionInfo; struct TransactionInfoPair; // This mutex guards mDatabases, see below. @@ -5713,10 +5713,14 @@ private: NS_DECL_NSIRUNNABLE }; -struct ConnectionPool::TransactionInfo final +class ConnectionPool::TransactionInfo final { friend class nsAutoPtr; + nsTHashtable> mBlocking; + nsTArray mBlockingOrdered; + +public: DatabaseInfo* mDatabaseInfo; const nsID mBackgroundChildLoggingId; const nsCString mDatabaseId; @@ -5724,7 +5728,6 @@ struct ConnectionPool::TransactionInfo final const int64_t mLoggingSerialNumber; const nsTArray mObjectStoreNames; nsTHashtable> mBlockedOn; - nsTHashtable> mBlocking; nsTArray> mQueuedRunnables; const bool mIsWriteTransaction; bool mRunning; @@ -5743,10 +5746,16 @@ struct ConnectionPool::TransactionInfo final TransactionDatabaseOperationBase* aTransactionOp); void - Schedule(); + AddBlockingTransaction(TransactionInfo* aTransactionInfo); + + void + RemoveBlockingTransactions(); private: ~TransactionInfo(); + + void + MaybeUnblock(TransactionInfo* aTransactionInfo); }; struct ConnectionPool::TransactionInfoPair final @@ -11745,7 +11754,7 @@ ConnectionPool::Start(const nsID& aBackgroundChildLoggingId, // Mark what we are blocking on. if (TransactionInfo* blockingRead = blockInfo->mLastBlockingReads) { transactionInfo->mBlockedOn.PutEntry(blockingRead); - blockingRead->mBlocking.PutEntry(transactionInfo); + blockingRead->AddBlockingTransaction(transactionInfo); } if (aIsWriteTransaction) { @@ -11756,7 +11765,7 @@ ConnectionPool::Start(const nsID& aBackgroundChildLoggingId, MOZ_ASSERT(blockingWrite); transactionInfo->mBlockedOn.PutEntry(blockingWrite); - blockingWrite->mBlocking.PutEntry(transactionInfo); + blockingWrite->AddBlockingTransaction(transactionInfo); } } @@ -12288,18 +12297,7 @@ ConnectionPool::NoteFinishedTransaction(uint64_t aTransactionId) blockInfo->mLastBlockingWrites.RemoveElement(transactionInfo); } - for (auto iter = transactionInfo->mBlocking.Iter(); - !iter.Done(); - iter.Next()) { - TransactionInfo* blockedInfo = iter.Get()->GetKey(); - MOZ_ASSERT(blockedInfo); - MOZ_ASSERT(blockedInfo->mBlockedOn.Contains(transactionInfo)); - - blockedInfo->mBlockedOn.RemoveEntry(transactionInfo); - if (!blockedInfo->mBlockedOn.Count()) { - blockedInfo->Schedule(); - } - } + transactionInfo->RemoveBlockingTransactions(); if (transactionInfo->mIsWriteTransaction) { MOZ_ASSERT(dbInfo->mWriteTransactionCount); @@ -13101,18 +13099,55 @@ TransactionInfo::~TransactionInfo() void ConnectionPool:: -TransactionInfo::Schedule() +TransactionInfo::AddBlockingTransaction(TransactionInfo* aTransactionInfo) { AssertIsOnBackgroundThread(); - MOZ_ASSERT(mDatabaseInfo); + MOZ_ASSERT(aTransactionInfo); - ConnectionPool* connectionPool = mDatabaseInfo->mConnectionPool; - MOZ_ASSERT(connectionPool); - connectionPool->AssertIsOnOwningThread(); + if (!mBlocking.Contains(aTransactionInfo)) { + mBlocking.PutEntry(aTransactionInfo); + mBlockingOrdered.AppendElement(aTransactionInfo); + } +} - Unused << - connectionPool->ScheduleTransaction(this, - /* aFromQueuedTransactions */ false); +void +ConnectionPool:: +TransactionInfo::RemoveBlockingTransactions() +{ + AssertIsOnBackgroundThread(); + + for (uint32_t index = 0, count = mBlockingOrdered.Length(); + index < count; + index++) { + TransactionInfo* blockedInfo = mBlockingOrdered[index]; + MOZ_ASSERT(blockedInfo); + + blockedInfo->MaybeUnblock(this); + } + + mBlocking.Clear(); + mBlockingOrdered.Clear(); +} + +void +ConnectionPool:: +TransactionInfo::MaybeUnblock(TransactionInfo* aTransactionInfo) +{ + AssertIsOnBackgroundThread(); + MOZ_ASSERT(mBlockedOn.Contains(aTransactionInfo)); + + mBlockedOn.RemoveEntry(aTransactionInfo); + if (!mBlockedOn.Count()) { + MOZ_ASSERT(mDatabaseInfo); + + ConnectionPool* connectionPool = mDatabaseInfo->mConnectionPool; + MOZ_ASSERT(connectionPool); + connectionPool->AssertIsOnOwningThread(); + + Unused << + connectionPool->ScheduleTransaction(this, + /* aFromQueuedTransactions */ false); + } } ConnectionPool:: diff --git a/testing/web-platform/meta/IndexedDB/transaction-lifetime-empty.html.ini b/testing/web-platform/meta/IndexedDB/transaction-lifetime-empty.html.ini deleted file mode 100644 index 0381b82582a2..000000000000 --- a/testing/web-platform/meta/IndexedDB/transaction-lifetime-empty.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[transaction-lifetime-empty.html] - type: testharness - disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1290853 From 04e71c59d277783b4d4d136ea9c4c884c9540728 Mon Sep 17 00:00:00 2001 From: m-r-m-s Date: Tue, 27 Sep 2016 08:11:47 +0200 Subject: [PATCH 005/102] Bug 1293704 - added adoptee/MS. r=ehsan --- extensions/spellcheck/locales/en-US/hunspell/en-US.dic | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extensions/spellcheck/locales/en-US/hunspell/en-US.dic b/extensions/spellcheck/locales/en-US/hunspell/en-US.dic index 74392b6e32fc..0b006936b130 100644 --- a/extensions/spellcheck/locales/en-US/hunspell/en-US.dic +++ b/extensions/spellcheck/locales/en-US/hunspell/en-US.dic @@ -1,4 +1,4 @@ -52342 +52343 0/nm 0th/pt 1/n1 @@ -13747,6 +13747,7 @@ adolescence/SM adolescent/SM adopt/AGVDS adoptable +adoptee/MS adopter/MS adoption/SM adorableness/M From 8026a8d792fcfec626d18a0c1f32633e71a9ee83 Mon Sep 17 00:00:00 2001 From: Tom Tung Date: Mon, 26 Sep 2016 09:54:10 +0800 Subject: [PATCH 006/102] Bug 1301966 - Prevent serviceWorker to modify response for sharedWorker and remove the second unexpected registration for the serviceWorker test. r=bkelly. --- .../test/serviceworkers/create_another_sharedWorker.html | 2 +- dom/workers/test/serviceworkers/fetch.js | 6 ++---- dom/workers/test/serviceworkers/hello.html | 9 +++++++++ dom/workers/test/serviceworkers/mochitest.ini | 2 +- dom/workers/test/serviceworkers/sharedWorker_fetch.js | 2 -- .../test/serviceworkers/test_fetch_integrity.html | 2 +- 6 files changed, 14 insertions(+), 9 deletions(-) create mode 100644 dom/workers/test/serviceworkers/hello.html diff --git a/dom/workers/test/serviceworkers/create_another_sharedWorker.html b/dom/workers/test/serviceworkers/create_another_sharedWorker.html index a63f3c59a412..f49194fa5049 100644 --- a/dom/workers/test/serviceworkers/create_another_sharedWorker.html +++ b/dom/workers/test/serviceworkers/create_another_sharedWorker.html @@ -3,4 +3,4 @@
Hello World
\ No newline at end of file + diff --git a/dom/workers/test/serviceworkers/fetch.js b/dom/workers/test/serviceworkers/fetch.js index 1fa24f81a4e6..38d20a638997 100644 --- a/dom/workers/test/serviceworkers/fetch.js +++ b/dom/workers/test/serviceworkers/fetch.js @@ -1,10 +1,8 @@ addEventListener('fetch', function(event) { if (event.request.url.indexOf("fail.html") !== -1) { - event.respondWith(fetch("serviceworker.html", {"integrity": "abc"})); + event.respondWith(fetch("hello.html", {"integrity": "abc"})); } else if (event.request.url.indexOf("fake.html") !== -1) { - event.respondWith(fetch("serviceworker.html")); - } else { - event.respondWith(new Response("Hello world")); + event.respondWith(fetch("hello.html")); } }); diff --git a/dom/workers/test/serviceworkers/hello.html b/dom/workers/test/serviceworkers/hello.html new file mode 100644 index 000000000000..97eb03c9025c --- /dev/null +++ b/dom/workers/test/serviceworkers/hello.html @@ -0,0 +1,9 @@ + + + + + + + Hello. + + diff --git a/dom/workers/test/serviceworkers/mochitest.ini b/dom/workers/test/serviceworkers/mochitest.ini index 14dcf9648977..df2949db00d6 100644 --- a/dom/workers/test/serviceworkers/mochitest.ini +++ b/dom/workers/test/serviceworkers/mochitest.ini @@ -210,7 +210,7 @@ support-files = sw_bad_mime_type.js^headers^ error_reporting_helpers.js fetch.js - serviceworker.html + hello.html create_another_sharedWorker.html sharedWorker_fetch.js diff --git a/dom/workers/test/serviceworkers/sharedWorker_fetch.js b/dom/workers/test/serviceworkers/sharedWorker_fetch.js index 8475498b4b2b..4970a1fd2fcf 100644 --- a/dom/workers/test/serviceworkers/sharedWorker_fetch.js +++ b/dom/workers/test/serviceworkers/sharedWorker_fetch.js @@ -27,5 +27,3 @@ onconnect = function(e) { } } } - - diff --git a/dom/workers/test/serviceworkers/test_fetch_integrity.html b/dom/workers/test/serviceworkers/test_fetch_integrity.html index 6b4ad6d0c7c9..50eb05581a8a 100644 --- a/dom/workers/test/serviceworkers/test_fetch_integrity.html +++ b/dom/workers/test/serviceworkers/test_fetch_integrity.html @@ -175,4 +175,4 @@ add_task(function* test_integrity_sharedWorker() { - \ No newline at end of file + From 626dd129aacb9bb461b49e6fc1c829a67a8b4217 Mon Sep 17 00:00:00 2001 From: Bevis Tseng Date: Mon, 12 Sep 2016 15:38:43 -0700 Subject: [PATCH 007/102] Bug 1302261 - Refresh Spec For Deleted Indexes. r=janv --- dom/indexedDB/IDBObjectStore.cpp | 29 ++++--- dom/indexedDB/IDBObjectStore.h | 1 + dom/indexedDB/IDBTransaction.cpp | 6 ++ dom/indexedDB/test/mochitest.ini | 6 ++ .../test/test_abort_deleted_index.html | 19 +++++ .../test/test_abort_deleted_objectStore.html | 19 +++++ .../test/unit/test_abort_deleted_index.js | 78 +++++++++++++++++++ .../unit/test_abort_deleted_objectStore.js | 74 ++++++++++++++++++ dom/indexedDB/test/unit/xpcshell-shared.ini | 2 + 9 files changed, 223 insertions(+), 11 deletions(-) create mode 100644 dom/indexedDB/test/test_abort_deleted_index.html create mode 100644 dom/indexedDB/test/test_abort_deleted_objectStore.html create mode 100644 dom/indexedDB/test/unit/test_abort_deleted_index.js create mode 100644 dom/indexedDB/test/unit/test_abort_deleted_objectStore.js diff --git a/dom/indexedDB/IDBObjectStore.cpp b/dom/indexedDB/IDBObjectStore.cpp index 9cbf3d787fcc..20e3920eb399 100644 --- a/dom/indexedDB/IDBObjectStore.cpp +++ b/dom/indexedDB/IDBObjectStore.cpp @@ -1554,7 +1554,8 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBObjectStore) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexes); + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexes) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDeletedIndexes) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBObjectStore) @@ -1562,7 +1563,8 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBObjectStore) // Don't unlink mTransaction! - NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexes); + NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexes) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mDeletedIndexes) tmp->mCachedKeyPath.setUndefined(); @@ -1774,13 +1776,11 @@ IDBObjectStore::CreateIndex(const nsAString& aName, } IDBTransaction* transaction = IDBTransaction::GetCurrent(); - if (!transaction || transaction != mTransaction) { + if (!transaction || transaction != mTransaction || !transaction->IsOpen()) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); return nullptr; } - MOZ_ASSERT(transaction->IsOpen()); - auto& indexes = const_cast&>(mSpec->indexes()); for (uint32_t count = indexes.Length(), index = 0; index < count; @@ -1888,13 +1888,11 @@ IDBObjectStore::DeleteIndex(const nsAString& aName, ErrorResult& aRv) } IDBTransaction* transaction = IDBTransaction::GetCurrent(); - if (!transaction || transaction != mTransaction) { + if (!transaction || transaction != mTransaction || !transaction->IsOpen()) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); return; } - MOZ_ASSERT(transaction->IsOpen()); - auto& metadataArray = const_cast&>(mSpec->indexes()); int64_t foundId = 0; @@ -1916,6 +1914,11 @@ IDBObjectStore::DeleteIndex(const nsAString& aName, ErrorResult& aRv) if (index->Id() == foundId) { index->NoteDeletion(); + + RefPtr* deletedIndex = + mDeletedIndexes.AppendElement(); + deletedIndex->swap(mIndexes[indexIndex]); + mIndexes.RemoveElementAt(indexIndex); break; } @@ -2130,6 +2133,12 @@ IDBObjectStore::RefreshSpec(bool aMayDelete) mIndexes[idxIndex]->RefreshMetadata(aMayDelete); } + for (uint32_t idxCount = mDeletedIndexes.Length(), idxIndex = 0; + idxIndex < idxCount; + idxIndex++) { + mDeletedIndexes[idxIndex]->RefreshMetadata(false); + } + found = true; break; } @@ -2202,13 +2211,11 @@ IDBObjectStore::SetName(const nsAString& aName, ErrorResult& aRv) } IDBTransaction* transaction = IDBTransaction::GetCurrent(); - if (!transaction || transaction != mTransaction) { + if (!transaction || transaction != mTransaction || !transaction->IsOpen()) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); return; } - MOZ_ASSERT(transaction->IsOpen()); - if (aName == mSpec->metadata().name()) { return; } diff --git a/dom/indexedDB/IDBObjectStore.h b/dom/indexedDB/IDBObjectStore.h index 31bcfbd726c0..7a255a4afc62 100644 --- a/dom/indexedDB/IDBObjectStore.h +++ b/dom/indexedDB/IDBObjectStore.h @@ -67,6 +67,7 @@ class IDBObjectStore final nsAutoPtr mDeletedSpec; nsTArray> mIndexes; + nsTArray> mDeletedIndexes; const int64_t mId; bool mRooted; diff --git a/dom/indexedDB/IDBTransaction.cpp b/dom/indexedDB/IDBTransaction.cpp index 6f1e61c74691..e0a30b56cb2a 100644 --- a/dom/indexedDB/IDBTransaction.cpp +++ b/dom/indexedDB/IDBTransaction.cpp @@ -653,6 +653,12 @@ IDBTransaction::AbortInternal(nsresult aAbortCode, mDatabase->RevertToPreviousState(); } + // We do the reversion only for the mObjectStores/mDeletedObjectStores but + // not for the mIndexes/mDeletedIndexes of each IDBObjectStore because it's + // time-consuming(O(m*n)) and mIndexes/mDeletedIndexes won't be used anymore + // in IDBObjectStore::(Create|Delete)Index() and IDBObjectStore::Index() in + // which all the executions are returned earlier by !transaction->IsOpen(). + const nsTArray& specArray = mDatabase->Spec()->objectStores(); diff --git a/dom/indexedDB/test/mochitest.ini b/dom/indexedDB/test/mochitest.ini index cb80a9ac47d2..557821b56453 100644 --- a/dom/indexedDB/test/mochitest.ini +++ b/dom/indexedDB/test/mochitest.ini @@ -19,6 +19,8 @@ support-files = service_worker_client.html third_party_iframe1.html third_party_iframe2.html + unit/test_abort_deleted_index.js + unit/test_abort_deleted_objectStore.js unit/test_add_put.js unit/test_add_twice_failure.js unit/test_advance.js @@ -115,6 +117,10 @@ support-files = webapp_clearBrowserData_appFrame.html webapp_clearBrowserData_browserFrame.html +[test_abort_deleted_index.html] +skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116 +[test_abort_deleted_objectStore.html] +skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116 [test_add_put.html] skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116 [test_add_twice_failure.html] diff --git a/dom/indexedDB/test/test_abort_deleted_index.html b/dom/indexedDB/test/test_abort_deleted_index.html new file mode 100644 index 000000000000..2c5eb6cbcb76 --- /dev/null +++ b/dom/indexedDB/test/test_abort_deleted_index.html @@ -0,0 +1,19 @@ + + + + Indexed Database Abort Deleted Index Test + + + + + + + + + + + + diff --git a/dom/indexedDB/test/test_abort_deleted_objectStore.html b/dom/indexedDB/test/test_abort_deleted_objectStore.html new file mode 100644 index 000000000000..a45e52d52f8f --- /dev/null +++ b/dom/indexedDB/test/test_abort_deleted_objectStore.html @@ -0,0 +1,19 @@ + + + + Indexed Database Abort Deleted ObjectStore Test + + + + + + + + + + + + diff --git a/dom/indexedDB/test/unit/test_abort_deleted_index.js b/dom/indexedDB/test/unit/test_abort_deleted_index.js new file mode 100644 index 000000000000..8bd1f6ae2cac --- /dev/null +++ b/dom/indexedDB/test/unit/test_abort_deleted_index.js @@ -0,0 +1,78 @@ +/** + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +var testGenerator = testSteps(); + +function testSteps() +{ + const name = this.window ? window.location.pathname : "Splendid Test"; + const storeName = "test store"; + const indexName_ToBeDeleted = "test index to be deleted"; + + info("Create index in v1."); + let request = indexedDB.open(name, 1); + request.onerror = errorHandler; + request.onupgradeneeded = grabEventAndContinueHandler; + request.onsuccess = unexpectedSuccessHandler; + let event = yield undefined; + + let db = event.target.result; + let txn = event.target.transaction; + + is(db.objectStoreNames.length, 0, "Correct objectStoreNames list"); + + let objectStore = db.createObjectStore(storeName, { keyPath: "foo" }); + is(db.objectStoreNames.length, 1, "Correct objectStoreNames list"); + is(db.objectStoreNames.item(0), objectStore.name, "Correct object store name"); + + // create index to be deleted later in v2. + objectStore.createIndex(indexName_ToBeDeleted, "foo"); + ok(objectStore.index(indexName_ToBeDeleted), "Index created."); + + txn.oncomplete = continueToNextStepSync; + yield undefined; + request.onsuccess = continueToNextStep; + yield undefined; + db.close(); + + info("Delete index in v2."); + request = indexedDB.open(name, 2); + request.onerror = errorHandler; + request.onupgradeneeded = grabEventAndContinueHandler; + request.onsuccess = unexpectedSuccessHandler; + event = yield undefined; + + db = event.target.result; + txn = event.target.transaction; + + objectStore = txn.objectStore(storeName); + let index = objectStore.index(indexName_ToBeDeleted); + ok(index, "index is valid."); + objectStore.deleteIndex(indexName_ToBeDeleted); + + // Aborting the transaction. + request.onerror = expectedErrorHandler("AbortError"); + txn.abort(); + try { + index.get('foo'); + ok(false, "TransactionInactiveError shall be thrown right after a deletion of an index is aborted."); + } catch (e) { + ok(e instanceof DOMException, "got a database exception"); + is(e.name, "TransactionInactiveError", "TransactionInactiveError shall be thrown right after a deletion of an index is aborted."); + } + + yield undefined; + + try { + index.get('foo'); + ok(false, "TransactionInactiveError shall be thrown after the transaction is inactive."); + } catch (e) { + ok(e instanceof DOMException, "got a database exception"); + is(e.name, "TransactionInactiveError", "TransactionInactiveError shall be thrown after the transaction is inactive."); + } + + finishTest(); + yield undefined; +} diff --git a/dom/indexedDB/test/unit/test_abort_deleted_objectStore.js b/dom/indexedDB/test/unit/test_abort_deleted_objectStore.js new file mode 100644 index 000000000000..98035b3dab72 --- /dev/null +++ b/dom/indexedDB/test/unit/test_abort_deleted_objectStore.js @@ -0,0 +1,74 @@ +/** + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +var testGenerator = testSteps(); + +function testSteps() +{ + const name = this.window ? window.location.pathname : "Splendid Test"; + const storeName_ToBeDeleted = "test store to be deleted"; + + info("Create objectStore in v1."); + let request = indexedDB.open(name, 1); + request.onerror = errorHandler; + request.onupgradeneeded = grabEventAndContinueHandler; + request.onsuccess = unexpectedSuccessHandler; + let event = yield undefined; + + let db = event.target.result; + let txn = event.target.transaction; + + is(db.objectStoreNames.length, 0, "Correct objectStoreNames list"); + + // create objectstore to be deleted later in v2. + db.createObjectStore(storeName_ToBeDeleted, { keyPath: "foo" }); + is(db.objectStoreNames.length, 1, "Correct objectStoreNames list"); + ok(db.objectStoreNames.contains(storeName_ToBeDeleted), "Correct name"); + + txn.oncomplete = continueToNextStepSync; + yield undefined; + request.onsuccess = continueToNextStep; + yield undefined; + db.close(); + + info("Delete objectStore in v2."); + request = indexedDB.open(name, 2); + request.onerror = errorHandler; + request.onupgradeneeded = grabEventAndContinueHandler; + request.onsuccess = unexpectedSuccessHandler; + event = yield undefined; + + db = event.target.result; + txn = event.target.transaction; + + let objectStore = txn.objectStore(storeName_ToBeDeleted); + ok(objectStore, "objectStore is available"); + + db.deleteObjectStore(storeName_ToBeDeleted); + + // Aborting the transaction. + request.onerror = expectedErrorHandler("AbortError"); + txn.abort(); + try { + objectStore.get('foo'); + ok(false, "TransactionInactiveError shall be thrown if the transaction is inactive."); + } catch (e) { + ok(e instanceof DOMException, "got a database exception"); + is(e.name, "TransactionInactiveError", "correct error"); + } + + yield undefined; + + try { + objectStore.get('foo'); + ok(false, "TransactionInactiveError shall be thrown if the transaction is inactive."); + } catch (e) { + ok(e instanceof DOMException, "got a database exception"); + is(e.name, "TransactionInactiveError", "correct error"); + } + + finishTest(); + yield undefined; +} diff --git a/dom/indexedDB/test/unit/xpcshell-shared.ini b/dom/indexedDB/test/unit/xpcshell-shared.ini index 1f02645669a2..05359097bd42 100644 --- a/dom/indexedDB/test/unit/xpcshell-shared.ini +++ b/dom/indexedDB/test/unit/xpcshell-shared.ini @@ -2,6 +2,8 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +[test_abort_deleted_index.js] +[test_abort_deleted_objectStore.js] [test_add_put.js] [test_add_twice_failure.js] [test_advance.js] From cb9811b6b4db77a450ecd2d4fe54dd188506a14b Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Wed, 17 Aug 2016 04:55:36 +0000 Subject: [PATCH 008/102] Bug 1295883 - Chase Linux scroll wheel behavior on Tier3 desktop Unix. r=smaug MozReview-Commit-ID: 7osYJCwDQev --HG-- extra : transplant_source : %F8%0CL%3D%C2d%92%B8%8AYd%C5%137h%ED%81Nt%3E --- dom/html/HTMLInputElement.cpp | 6 +++--- dom/html/HTMLInputElement.h | 2 +- dom/html/test/mochitest.ini | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index 6f48db718416..229013926e4d 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -3442,7 +3442,7 @@ HTMLInputElement::Focus(ErrorResult& aError) return; } -#if defined(XP_WIN) || defined(XP_LINUX) +#if !defined(ANDROID) && !defined(XP_MACOSX) bool HTMLInputElement::IsNodeApzAwareInternal() const { @@ -4538,7 +4538,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor) } break; } -#if defined(XP_WIN) || defined(XP_LINUX) +#if !defined(ANDROID) && !defined(XP_MACOSX) case eWheel: { // Handle wheel events as increasing / decreasing the input element's // value when it's focused and it's type is number or range. @@ -6203,7 +6203,7 @@ FireEventForAccessibility(nsIDOMHTMLInputElement* aTarget, void HTMLInputElement::UpdateApzAwareFlag() { -#if defined(XP_WIN) || defined(XP_LINUX) +#if !defined(ANDROID) && !defined(XP_MACOSX) if ((mType == NS_FORM_INPUT_NUMBER) || (mType == NS_FORM_INPUT_RANGE)) { SetMayBeApzAware(); } diff --git a/dom/html/HTMLInputElement.h b/dom/html/HTMLInputElement.h index 0f9dc3946ab4..bb83b304b822 100644 --- a/dom/html/HTMLInputElement.h +++ b/dom/html/HTMLInputElement.h @@ -135,7 +135,7 @@ public: virtual void Focus(ErrorResult& aError) override; // nsINode -#if defined(XP_WIN) || defined(XP_LINUX) +#if !defined(ANDROID) && !defined(XP_MACOSX) virtual bool IsNodeApzAwareInternal() const override; #endif diff --git a/dom/html/test/mochitest.ini b/dom/html/test/mochitest.ini index 09908c97dd5e..a1964e84b4fe 100644 --- a/dom/html/test/mochitest.ini +++ b/dom/html/test/mochitest.ini @@ -622,11 +622,11 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' [test_bug1250401.html] [test_bug1260664.html] [test_bug1261673.html] -skip-if = (os != 'win' && os != 'linux') +skip-if = (os == 'android' || os == 'mac') [test_bug1261674-1.html] -skip-if = (os != 'win' && os != 'linux') +skip-if = (os == 'android' || os == 'mac') [test_bug1261674-2.html] -skip-if = (os != 'win' && os != 'linux') +skip-if = (os == 'android' || os == 'mac') [test_bug1260704.html] [test_allowMedia.html] [test_bug1292522_same_domain_with_different_port_number.html] From cb9968ef9d26d7671785e15b0dafe6da455c3d64 Mon Sep 17 00:00:00 2001 From: James Cheng Date: Fri, 23 Sep 2016 14:33:01 +0800 Subject: [PATCH 009/102] Bug 1304258 - Part1 - Add Util Method to Create JNI Array Object. r=jchen MozReview-Commit-ID: INXNelhQzuR --HG-- extra : transplant_source : %1F%A3%E1%E3/%B7%5Em%D7%0F%CA%1Ah%B5%16U%9Bn%89U --- widget/android/jni/Refs.h | 15 +++++++++++++++ widget/android/jni/Types.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/widget/android/jni/Refs.h b/widget/android/jni/Refs.h index 139494c48613..a99eea3e04b9 100644 --- a/widget/android/jni/Refs.h +++ b/widget/android/jni/Refs.h @@ -707,6 +707,21 @@ public: : Base(ctx) {} + static typename Base::LocalRef New(const ElementType* data, size_t length) { + using JNIElemType = typename detail::TypeAdapter::JNIType; + static_assert(sizeof(ElementType) == sizeof(JNIElemType), + "Size of native type must match size of JNI type"); + JNIEnv* const jenv = mozilla::jni::GetEnvForThread(); + auto result = + (jenv->*detail::TypeAdapter::NewArray)(length); + MOZ_CATCH_JNI_EXCEPTION(jenv); + (jenv->*detail::TypeAdapter::SetArray)( + result, jsize(0), length, + reinterpret_cast(data)); + MOZ_CATCH_JNI_EXCEPTION(jenv); + return Base::LocalRef::Adopt(jenv, result); + } + size_t Length() const { const size_t ret = Base::Env()->GetArrayLength(Base::Instance()); diff --git a/widget/android/jni/Types.h b/widget/android/jni/Types.h index 10fb5702599e..a083d3e50d08 100644 --- a/widget/android/jni/Types.h +++ b/widget/android/jni/Types.h @@ -107,6 +107,8 @@ template struct TypeAdapter static constexpr auto Set = &JNIEnv::Set ## JNIName ## Field; \ static constexpr auto StaticSet = &JNIEnv::SetStatic ## JNIName ## Field; \ static constexpr auto GetArray = &JNIEnv::Get ## JNIName ## ArrayRegion; \ + static constexpr auto SetArray = &JNIEnv::Set ## JNIName ## ArrayRegion; \ + static constexpr auto NewArray = &JNIEnv::New ## JNIName ## Array; \ \ static JNIType FromNative(JNIEnv*, NativeType val) { \ return static_cast(val); \ From 345dc9fc9d8871f1ce49c3518420ebf4c95d1e0f Mon Sep 17 00:00:00 2001 From: James Cheng Date: Fri, 23 Sep 2016 14:33:47 +0800 Subject: [PATCH 010/102] Bug 1304258 - Part2 - Use XXXArray::New instead. r=jchen MozReview-Commit-ID: 2bqO7839fX2 --HG-- extra : transplant_source : Y%A7%17%04%97%06%C8%96%29%8C%1Dy%98%AD%04%DB%BA%B9%9A%C3 --- .../android/AndroidDecoderModule.cpp | 43 +++++-------------- 1 file changed, 11 insertions(+), 32 deletions(-) diff --git a/dom/media/platforms/android/AndroidDecoderModule.cpp b/dom/media/platforms/android/AndroidDecoderModule.cpp index 03bef68cbfd5..0fcbe1c91718 100644 --- a/dom/media/platforms/android/AndroidDecoderModule.cpp +++ b/dom/media/platforms/android/AndroidDecoderModule.cpp @@ -29,33 +29,6 @@ using namespace mozilla::gl; using namespace mozilla::java::sdk; using media::TimeUnit; -namespace { - template - mozilla::jni::ByteArray::LocalRef - CreateAndInitJByteArray(const T& data, jsize length) - { - JNIEnv* const jenv = mozilla::jni::GetEnvForThread(); - jbyteArray result = jenv->NewByteArray(length); - MOZ_CATCH_JNI_EXCEPTION(jenv); - jenv->SetByteArrayRegion(result, 0, length, reinterpret_cast(const_cast(data))); - MOZ_CATCH_JNI_EXCEPTION(jenv); - return mozilla::jni::ByteArray::LocalRef::Adopt(jenv, result); - } - - template - mozilla::jni::IntArray::LocalRef - CreateAndInitJIntArray(const T& data, jsize length) - { - JNIEnv* const jenv = mozilla::jni::GetEnvForThread(); - jintArray result = jenv->NewIntArray(length); - MOZ_CATCH_JNI_EXCEPTION(jenv); - jenv->SetIntArrayRegion(result, 0, length, reinterpret_cast(const_cast(data))); - MOZ_CATCH_JNI_EXCEPTION(jenv); - return mozilla::jni::IntArray::LocalRef::Adopt(jenv, result); - } -} - - namespace mozilla { mozilla::LazyLogModule sAndroidDecoderModuleLog("AndroidDecoderModule"); @@ -125,11 +98,17 @@ GetCryptoInfoFromSample(const MediaRawData* aSample) tempIV.AppendElement(0); } - auto numBytesOfPlainData = CreateAndInitJIntArray(&plainSizes[0], plainSizes.Length()); - auto numBytesOfEncryptedData = CreateAndInitJIntArray(&cryptoObj.mEncryptedSizes[0], - cryptoObj.mEncryptedSizes.Length()); - auto iv = CreateAndInitJByteArray(&tempIV[0], tempIV.Length()); - auto keyId = CreateAndInitJByteArray(&cryptoObj.mKeyId[0], cryptoObj.mKeyId.Length()); + auto numBytesOfPlainData = mozilla::jni::IntArray::New( + reinterpret_cast(&plainSizes[0]), + plainSizes.Length()); + + auto numBytesOfEncryptedData = + mozilla::jni::IntArray::New(reinterpret_cast(&cryptoObj.mEncryptedSizes[0]), + cryptoObj.mEncryptedSizes.Length()); + auto iv = mozilla::jni::ByteArray::New(reinterpret_cast(&tempIV[0]), + tempIV.Length()); + auto keyId = mozilla::jni::ByteArray::New(reinterpret_cast(&cryptoObj.mKeyId[0]), + cryptoObj.mKeyId.Length()); cryptoInfo->Set(numSubSamples, numBytesOfPlainData, numBytesOfEncryptedData, From 5d3595ab735304ebc82258e0458a7de16dcbb84f Mon Sep 17 00:00:00 2001 From: Rob Thijssen Date: Wed, 21 Sep 2016 17:47:44 +0100 Subject: [PATCH 011/102] Bug 1304354 - disambiguate Windows build platform in treeherder; r=dustin MozReview-Commit-ID: 7RV9IDFDDoH --HG-- extra : transplant_source : %F7Am%1E%C9%EC%EE%C8h%B3%C6%ED%7B%91%F4R%7Fo%9Dz --- taskcluster/ci/build/windows.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/taskcluster/ci/build/windows.yml b/taskcluster/ci/build/windows.yml index 78c1e00f5343..342a6b0b5369 100644 --- a/taskcluster/ci/build/windows.yml +++ b/taskcluster/ci/build/windows.yml @@ -5,7 +5,7 @@ win32/debug: job-name: gecko-v2: win32-debug treeherder: - platform: windowsxp/debug + platform: windows2012-32/debug symbol: tc(B) tier: 2 worker-type: aws-provisioner-v1/gecko-{level}-b-win2012 @@ -25,7 +25,7 @@ win32/opt: job-name: gecko-v2: win32-opt treeherder: - platform: windowsxp/opt + platform: windows2012-32/opt symbol: tc(B) tier: 2 worker-type: aws-provisioner-v1/gecko-{level}-b-win2012 @@ -45,7 +45,7 @@ win64/debug: job-name: gecko-v2: win64-debug treeherder: - platform: windows8-64/debug + platform: windows2012-64/debug symbol: tc(B) tier: 2 worker-type: aws-provisioner-v1/gecko-{level}-b-win2012 @@ -65,7 +65,7 @@ win64/opt: job-name: gecko-v2: win64-opt treeherder: - platform: windows8-64/opt + platform: windows2012-64/opt symbol: tc(B) tier: 2 worker-type: aws-provisioner-v1/gecko-{level}-b-win2012 From ba6cb5196e9f21c62181e9ffde73d80f025b4785 Mon Sep 17 00:00:00 2001 From: Thomas Wisniewski Date: Fri, 23 Sep 2016 21:10:01 -0400 Subject: [PATCH 012/102] Bug 1305202 - Use NullString() more and remove superfluous Truncates(). r=smaug --- dom/ipc/Blob.cpp | 10 ++-------- dom/json/nsJSON.cpp | 2 -- dom/plugins/ipc/PluginMessageUtils.h | 4 +--- js/xpconnect/src/XPCConvert.cpp | 1 - parser/html/nsHtml5TreeOperation.cpp | 4 +--- storage/Variant.h | 2 -- storage/mozStorageArgValueArray.cpp | 2 -- storage/mozStorageStatement.cpp | 2 -- toolkit/components/places/nsNavBookmarks.cpp | 6 ++---- xpcom/ds/nsVariant.cpp | 1 - 10 files changed, 6 insertions(+), 28 deletions(-) diff --git a/dom/ipc/Blob.cpp b/dom/ipc/Blob.cpp index b51665e9f716..22d76c9bd6cb 100644 --- a/dom/ipc/Blob.cpp +++ b/dom/ipc/Blob.cpp @@ -3574,10 +3574,7 @@ BlobChild::SetMysteryBlobInfo(const nsString& aContentType, uint64_t aLength) MOZ_ASSERT(mBlobImpl); MOZ_ASSERT(mRemoteBlobImpl); - nsString voidString; - voidString.SetIsVoid(true); - - mBlobImpl->SetLazyData(voidString, aContentType, aLength, INT64_MAX); + mBlobImpl->SetLazyData(NullString(), aContentType, aLength, INT64_MAX); NormalBlobConstructorParams params(aContentType, aLength, @@ -4400,10 +4397,7 @@ BlobParent::RecvResolveMystery(const ResolveMysteryParams& aParams) return false; } - nsString voidString; - voidString.SetIsVoid(true); - - mBlobImpl->SetLazyData(voidString, + mBlobImpl->SetLazyData(NullString(), params.contentType(), params.length(), INT64_MAX); diff --git a/dom/json/nsJSON.cpp b/dom/json/nsJSON.cpp index a3d1f4f00f46..f46606fc5a81 100644 --- a/dom/json/nsJSON.cpp +++ b/dom/json/nsJSON.cpp @@ -70,7 +70,6 @@ nsJSON::Encode(JS::Handle aValue, JSContext* cx, uint8_t aArgc, return rv; if (aArgc == 0) { - aJSON.Truncate(); aJSON.SetIsVoid(true); return NS_OK; } @@ -83,7 +82,6 @@ nsJSON::Encode(JS::Handle aValue, JSContext* cx, uint8_t aArgc, rv = NS_OK; // if we didn't consume anything, it's not JSON, so return null if (!writer.DidWrite()) { - aJSON.Truncate(); aJSON.SetIsVoid(true); } else { writer.FlushBuffer(); diff --git a/dom/plugins/ipc/PluginMessageUtils.h b/dom/plugins/ipc/PluginMessageUtils.h index d58c38989244..0150eac10cda 100644 --- a/dom/plugins/ipc/PluginMessageUtils.h +++ b/dom/plugins/ipc/PluginMessageUtils.h @@ -253,9 +253,7 @@ inline nsCString NullableString(const char* aString) { if (!aString) { - nsCString str; - str.SetIsVoid(true); - return str; + return NullCString(); } return nsCString(aString); } diff --git a/js/xpconnect/src/XPCConvert.cpp b/js/xpconnect/src/XPCConvert.cpp index 23e1731a9d78..feea398cf543 100644 --- a/js/xpconnect/src/XPCConvert.cpp +++ b/js/xpconnect/src/XPCConvert.cpp @@ -640,7 +640,6 @@ XPCConvert::JSData2Native(void* d, HandleValue s, { if (s.isNull() || s.isUndefined()) { nsACString* rs = *((nsACString**)d); - rs->Truncate(); rs->SetIsVoid(true); return true; } diff --git a/parser/html/nsHtml5TreeOperation.cpp b/parser/html/nsHtml5TreeOperation.cpp index 3ba9ec975b8b..af246a253929 100644 --- a/parser/html/nsHtml5TreeOperation.cpp +++ b/parser/html/nsHtml5TreeOperation.cpp @@ -565,14 +565,12 @@ nsHtml5TreeOperation::AppendDoctypeToDocument(nsIAtom* aName, // Adapted from nsXMLContentSink // Create a new doctype node nsCOMPtr docType; - nsAutoString voidString; - voidString.SetIsVoid(true); NS_NewDOMDocumentType(getter_AddRefs(docType), aBuilder->GetNodeInfoManager(), aName, aPublicId, aSystemId, - voidString); + NullString()); NS_ASSERTION(docType, "Doctype creation failed."); nsCOMPtr asContent = do_QueryInterface(docType); return AppendToDocument(asContent, aBuilder); diff --git a/storage/Variant.h b/storage/Variant.h index 988851ad8084..265abb02aede 100644 --- a/storage/Variant.h +++ b/storage/Variant.h @@ -357,7 +357,6 @@ public: NS_IMETHOD GetAsAUTF8String(nsACString &_str) { // Return a void string. - _str.Truncate(0); _str.SetIsVoid(true); return NS_OK; } @@ -365,7 +364,6 @@ public: NS_IMETHOD GetAsAString(nsAString &_str) { // Return a void string. - _str.Truncate(0); _str.SetIsVoid(true); return NS_OK; } diff --git a/storage/mozStorageArgValueArray.cpp b/storage/mozStorageArgValueArray.cpp index 3b9daab2fd08..40d67a4cd897 100644 --- a/storage/mozStorageArgValueArray.cpp +++ b/storage/mozStorageArgValueArray.cpp @@ -108,7 +108,6 @@ ArgValueArray::GetUTF8String(uint32_t aIndex, if (::sqlite3_value_type(mArgv[aIndex]) == SQLITE_NULL) { // NULL columns should have IsVoid set to distinguish them from an empty // string. - _value.Truncate(0); _value.SetIsVoid(true); } else { @@ -127,7 +126,6 @@ ArgValueArray::GetString(uint32_t aIndex, if (::sqlite3_value_type(mArgv[aIndex]) == SQLITE_NULL) { // NULL columns should have IsVoid set to distinguish them from an empty // string. - _value.Truncate(0); _value.SetIsVoid(true); } else { _value.Assign(static_cast(::sqlite3_value_text16(mArgv[aIndex])), diff --git a/storage/mozStorageStatement.cpp b/storage/mozStorageStatement.cpp index 3733a7ae15b1..6f032dde54a8 100644 --- a/storage/mozStorageStatement.cpp +++ b/storage/mozStorageStatement.cpp @@ -772,7 +772,6 @@ Statement::GetUTF8String(uint32_t aIndex, if (type == mozIStorageStatement::VALUE_TYPE_NULL) { // NULL columns should have IsVoid set to distinguish them from the empty // string. - _value.Truncate(0); _value.SetIsVoid(true); } else { @@ -795,7 +794,6 @@ Statement::GetString(uint32_t aIndex, if (type == mozIStorageStatement::VALUE_TYPE_NULL) { // NULL columns should have IsVoid set to distinguish them from the empty // string. - _value.Truncate(0); _value.SetIsVoid(true); } else { const char16_t *value = diff --git a/toolkit/components/places/nsNavBookmarks.cpp b/toolkit/components/places/nsNavBookmarks.cpp index 74da2203da3c..d2459ac8da8e 100644 --- a/toolkit/components/places/nsNavBookmarks.cpp +++ b/toolkit/components/places/nsNavBookmarks.cpp @@ -799,11 +799,9 @@ nsNavBookmarks::InsertSeparator(int64_t aParent, *aNewItemId = -1; // Set a NULL title rather than an empty string. - nsCString voidString; - voidString.SetIsVoid(true); nsAutoCString guid(aGUID); PRTime dateAdded = RoundedPRNow(); - rv = InsertBookmarkInDB(-1, SEPARATOR, aParent, index, voidString, dateAdded, + rv = InsertBookmarkInDB(-1, SEPARATOR, aParent, index, NullCString(), dateAdded, 0, folderGuid, grandParentId, nullptr, aSource, aNewItemId, guid); NS_ENSURE_SUCCESS(rv, rv); @@ -814,7 +812,7 @@ nsNavBookmarks::InsertSeparator(int64_t aParent, NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers, nsINavBookmarkObserver, OnItemAdded(*aNewItemId, aParent, index, TYPE_SEPARATOR, - nullptr, voidString, dateAdded, guid, folderGuid, + nullptr, NullCString(), dateAdded, guid, folderGuid, aSource)); return NS_OK; diff --git a/xpcom/ds/nsVariant.cpp b/xpcom/ds/nsVariant.cpp index 6edae9f4f32b..edb020139a6e 100644 --- a/xpcom/ds/nsVariant.cpp +++ b/xpcom/ds/nsVariant.cpp @@ -766,7 +766,6 @@ nsDiscriminatedUnion::ToString(nsACString& aOutString) const case nsIDataType::VTYPE_VOID: case nsIDataType::VTYPE_EMPTY: - aOutString.Truncate(); aOutString.SetIsVoid(true); return NS_OK; From cd3ee4c9514b8c439baeb7684477518a896486de Mon Sep 17 00:00:00 2001 From: Honza Bambas Date: Tue, 22 Mar 2016 11:42:00 +0100 Subject: [PATCH 013/102] Bug 1231565 - (Part 1) Basic test for alt-data representation in cache r=honzab --- netwerk/cache2/CacheStorageService.cpp | 27 +++++ netwerk/cache2/nsICacheTesting.idl | 3 + netwerk/test/unit/test_alt-data_simple.js | 111 ++++++++++++++++++ netwerk/test/unit/xpcshell.ini | 1 + .../unit_ipc/test_alt-data_simple_wrap.js | 3 + netwerk/test/unit_ipc/xpcshell.ini | 2 + 6 files changed, 147 insertions(+) create mode 100644 netwerk/test/unit/test_alt-data_simple.js create mode 100644 netwerk/test/unit_ipc/test_alt-data_simple_wrap.js diff --git a/netwerk/cache2/CacheStorageService.cpp b/netwerk/cache2/CacheStorageService.cpp index 5869ddeaea46..175bb3bc6b0b 100644 --- a/netwerk/cache2/CacheStorageService.cpp +++ b/netwerk/cache2/CacheStorageService.cpp @@ -2251,5 +2251,32 @@ CacheStorageService::ResumeCacheIOThread() return NS_OK; } +NS_IMETHODIMP +CacheStorageService::Flush(nsIObserver* aObserver) +{ + RefPtr thread = CacheFileIOManager::IOThread(); + if (!thread) { + return NS_ERROR_NOT_AVAILABLE; + } + + nsCOMPtr observerService = + mozilla::services::GetObserverService(); + if (!observerService) { + return NS_ERROR_NOT_AVAILABLE; + } + + // Adding as weak, the consumer is responsible to keep the reference + // until notified. + observerService->AddObserver(aObserver, "cacheservice:purge-memory-pools", false); + + // This runnable will do the purging and when done, notifies the above observer. + // We dispatch it to the CLOSE level, so all data writes scheduled up to this time + // will be done before this purging happens. + RefPtr r = + new CacheStorageService::PurgeFromMemoryRunnable(this, CacheEntry::PURGE_WHOLE); + + return thread->Dispatch(r, CacheIOThread::CLOSE); +} + } // namespace net } // namespace mozilla diff --git a/netwerk/cache2/nsICacheTesting.idl b/netwerk/cache2/nsICacheTesting.idl index d71891f0daec..15704f7caa82 100644 --- a/netwerk/cache2/nsICacheTesting.idl +++ b/netwerk/cache2/nsICacheTesting.idl @@ -4,6 +4,8 @@ #include "nsISupports.idl" +interface nsIObserver; + /** * This is an internal interface used only for testing purposes. * @@ -14,4 +16,5 @@ interface nsICacheTesting : nsISupports { void suspendCacheIOThread(in uint32_t aLevel); void resumeCacheIOThread(); + void flush(in nsIObserver aObserver); }; diff --git a/netwerk/test/unit/test_alt-data_simple.js b/netwerk/test/unit/test_alt-data_simple.js new file mode 100644 index 000000000000..6066eddf0835 --- /dev/null +++ b/netwerk/test/unit/test_alt-data_simple.js @@ -0,0 +1,111 @@ +/** + * Test for the "alternative data stream" stored withing a cache entry. + * + * - we load a URL with preference for an alt data (check what we get is the raw data, + * since there was nothing previously cached) + * - we store the alt data along the channel (to the cache entry) + * - we flush the HTTP cache + * - we reload the same URL using a new channel, again prefering the alt data be loaded + * - this time the alt data must arive + */ + +Cu.import("resource://testing-common/httpd.js"); +Cu.import("resource://gre/modules/NetUtil.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +XPCOMUtils.defineLazyGetter(this, "URL", function() { + return "http://localhost:" + httpServer.identity.primaryPort + "/content"; +}); + +var httpServer = null; + +function make_channel(url, callback, ctx) { + return NetUtil.newChannel({uri: url, loadUsingSystemPrincipal: true}); +} + +const responseContent = "response body"; +const altContent = "!@#$%^&*()"; +const altContentType = "text/binary"; + +var servedNotModified = false; + +function contentHandler(metadata, response) +{ + response.setHeader("Content-Type", "text/plain"); + response.setHeader("Cache-Control", "no-cache"); + response.setHeader("ETag", "test-etag1"); + + try { + var etag = metadata.getHeader("If-None-Match"); + } catch(ex) { + var etag = ""; + } + + if (etag == "test-etag1") { + response.setStatusLine(metadata.httpVersion, 304, "Not Modified"); + servedNotModified = true; + } else { + response.bodyOutputStream.write(responseContent, responseContent.length); + } +} + +function run_test() +{ + do_get_profile(); + httpServer = new HttpServer(); + httpServer.registerPathHandler("/content", contentHandler); + httpServer.start(-1); + + var chan = make_channel(URL); + + var cc = chan.QueryInterface(Ci.nsICacheInfoChannel); + cc.preferAlternativeDataType(altContentType); + + chan.asyncOpen2(new ChannelListener(readServerContent, null, CL_ALLOW_UNKNOWN_CL)); + do_test_pending(); +} + +function readServerContent(request, buffer) +{ + var cc = request.QueryInterface(Ci.nsICacheInfoChannel); + + do_check_eq(buffer, responseContent); + do_check_eq(cc.alternativeDataType, ""); + + do_execute_soon(() => { + var os = cc.openAlternativeOutputStream(altContentType); + os.write(altContent, altContent.length); + os.close(); + + do_execute_soon(flushAndOpenAltChannel); + }); +} + +// needs to be rooted +var cacheFlushObserver = cacheFlushObserver = { observe: function() { + cacheFlushObserver = null; + + var chan = make_channel(URL); + var cc = chan.QueryInterface(Ci.nsICacheInfoChannel); + cc.preferAlternativeDataType(altContentType); + + chan.asyncOpen2(new ChannelListener(readAltContent, null)); +}}; + +function flushAndOpenAltChannel() +{ + // We need to do a GC pass to ensure the cache entry has been freed. + gc(); + Services.cache2.QueryInterface(Ci.nsICacheTesting).flush(cacheFlushObserver); +} + +function readAltContent(request, buffer) +{ + var cc = request.QueryInterface(Ci.nsICacheInfoChannel); + + do_check_eq(servedNotModified, true); + do_check_eq(cc.alternativeDataType, altContentType); + do_check_eq(buffer, altContent); + + httpServer.stop(do_test_finished); +} diff --git a/netwerk/test/unit/xpcshell.ini b/netwerk/test/unit/xpcshell.ini index a53cc0cc5396..73a4ce4b1730 100644 --- a/netwerk/test/unit/xpcshell.ini +++ b/netwerk/test/unit/xpcshell.ini @@ -358,6 +358,7 @@ skip-if = os == "android" [test_packaged_app_bug1214079.js] [test_bug412457.js] [test_bug464591.js] +[test_alt-data_simple.js] [test_cache-control_request.js] [test_bug1279246.js] [test_throttlequeue.js] diff --git a/netwerk/test/unit_ipc/test_alt-data_simple_wrap.js b/netwerk/test/unit_ipc/test_alt-data_simple_wrap.js new file mode 100644 index 000000000000..04441c22a467 --- /dev/null +++ b/netwerk/test/unit_ipc/test_alt-data_simple_wrap.js @@ -0,0 +1,3 @@ +function run_test() { + run_test_in_child("../unit/test_alt-data_simple.js"); +} diff --git a/netwerk/test/unit_ipc/xpcshell.ini b/netwerk/test/unit_ipc/xpcshell.ini index 70760b382d05..ea7d7c22ae56 100644 --- a/netwerk/test/unit_ipc/xpcshell.ini +++ b/netwerk/test/unit_ipc/xpcshell.ini @@ -54,6 +54,7 @@ support-files = child_app_offline.js !/netwerk/test/unit/data/test_readline7.txt !/netwerk/test/unit/data/test_readline8.txt !/netwerk/test/unit/data/signed_win.exe + !/netwerk/test/unit/test_alt-data_simple.js [test_bug528292_wrap.js] [test_bug248970_cookie_wrap.js] @@ -93,6 +94,7 @@ skip-if = true [test_reply_without_content_type_wrap.js] [test_app_offline_http.js] [test_getHost_wrap.js] +[test_alt-data_simple_wrap.js] [test_app_offline_notifications.js] [test_original_sent_received_head_wrap.js] [test_channel_id.js] From 76d2cd8b5d2b4ac1586463c3920c456b74df297b Mon Sep 17 00:00:00 2001 From: Valentin Gosu Date: Mon, 11 Apr 2016 05:17:02 +0200 Subject: [PATCH 014/102] Bug 1231565 - (Part 2) Allow storing alternate data in the HTTP cache r=honzab * Add PAltDataOutputStream.ipdl to be able to open an OutputStream to the cache entry in the child process * AltDataOutputStreamChild/Parent are Main Thread only for now. * Adds methods for reading and writing alt-data to nsICacheInfoChannel.idl * Keep a ref of the cache entry after OnStopRequest in case the consumer tries to open the alt-data output stream MozReview-Commit-ID: jlraDI97Hg --- netwerk/base/nsICacheInfoChannel.idl | 29 ++++ netwerk/cache2/CacheEntry.cpp | 44 ++++- netwerk/cache2/CacheEntry.h | 1 + netwerk/cache2/OldWrappers.h | 9 ++ netwerk/cache2/nsICacheEntry.idl | 23 +++ netwerk/ipc/NeckoChannelParams.ipdlh | 1 + netwerk/ipc/NeckoChild.cpp | 20 +++ netwerk/ipc/NeckoChild.h | 4 + netwerk/ipc/NeckoParent.cpp | 26 +++ netwerk/ipc/NeckoParent.h | 6 + netwerk/ipc/PNecko.ipdl | 4 + .../http/AltDataOutputStreamChild.cpp | 151 ++++++++++++++++++ .../protocol/http/AltDataOutputStreamChild.h | 46 ++++++ .../http/AltDataOutputStreamParent.cpp | 71 ++++++++ .../protocol/http/AltDataOutputStreamParent.h | 52 ++++++ netwerk/protocol/http/HttpBaseChannel.cpp | 13 ++ netwerk/protocol/http/HttpBaseChannel.h | 9 ++ netwerk/protocol/http/HttpChannelChild.cpp | 58 ++++++- netwerk/protocol/http/HttpChannelChild.h | 6 +- netwerk/protocol/http/HttpChannelParent.cpp | 23 ++- netwerk/protocol/http/HttpChannelParent.h | 5 +- .../protocol/http/PAltDataOutputStream.ipdl | 32 ++++ netwerk/protocol/http/PHttpChannel.ipdl | 3 +- netwerk/protocol/http/moz.build | 5 + netwerk/protocol/http/nsHttpChannel.cpp | 62 ++++++- netwerk/protocol/http/nsHttpChannel.h | 6 + 26 files changed, 694 insertions(+), 15 deletions(-) create mode 100644 netwerk/protocol/http/AltDataOutputStreamChild.cpp create mode 100644 netwerk/protocol/http/AltDataOutputStreamChild.h create mode 100644 netwerk/protocol/http/AltDataOutputStreamParent.cpp create mode 100644 netwerk/protocol/http/AltDataOutputStreamParent.h create mode 100644 netwerk/protocol/http/PAltDataOutputStream.ipdl diff --git a/netwerk/base/nsICacheInfoChannel.idl b/netwerk/base/nsICacheInfoChannel.idl index 9ad97309f130..f6d3c7b735cf 100644 --- a/netwerk/base/nsICacheInfoChannel.idl +++ b/netwerk/base/nsICacheInfoChannel.idl @@ -4,6 +4,8 @@ #include "nsISupports.idl" +interface nsIOutputStream; + [scriptable, uuid(72c34415-c6eb-48af-851f-772fa9ee5972)] interface nsICacheInfoChannel : nsISupports { @@ -52,4 +54,31 @@ interface nsICacheInfoChannel : nsISupports * channel being the default load group's channel. */ attribute boolean allowStaleCacheContent; + + /** + * Calling this method instructs the channel to serve the alternative data + * if that was previously saved in the cache, otherwise it will serve the + * real data. + * Must be called before AsyncOpen. + */ + void preferAlternativeDataType(in ACString type); + + /** + * Holds the type of the alternative data representation that the channel + * is returning. + * Is empty string if no alternative data representation was requested, or + * if the requested representation wasn't found in the cache. + * Can only be called during or after OnStartRequest. + */ + readonly attribute ACString alternativeDataType; + + /** + * Opens and returns an output stream that a consumer may use to save an + * alternate representation of the data. + * Must be called after the OnStopRequest that delivered the real data. + * The consumer may choose to replace the saved alt representation. + * Opening the output stream will fail if there are any open input streams + * reading the already saved alt representation. + */ + nsIOutputStream openAlternativeOutputStream(in ACString type); }; diff --git a/netwerk/cache2/CacheEntry.cpp b/netwerk/cache2/CacheEntry.cpp index dba9e72b1dd8..1122fe3fc142 100644 --- a/netwerk/cache2/CacheEntry.cpp +++ b/netwerk/cache2/CacheEntry.cpp @@ -1128,6 +1128,19 @@ NS_IMETHODIMP CacheEntry::SetExpirationTime(uint32_t aExpirationTime) NS_IMETHODIMP CacheEntry::OpenInputStream(int64_t offset, nsIInputStream * *_retval) { LOG(("CacheEntry::OpenInputStream [this=%p]", this)); + return OpenInputStreamInternal(offset, nullptr, _retval); +} + +NS_IMETHODIMP CacheEntry::OpenAlternativeInputStream(const nsACString & type, nsIInputStream * *_retval) +{ + LOG(("CacheEntry::OpenAlternativeInputStream [this=%p, type=%s]", this, + PromiseFlatCString(type).get())); + return OpenInputStreamInternal(0, PromiseFlatCString(type).get(), _retval); +} + +nsresult CacheEntry::OpenInputStreamInternal(int64_t offset, const char *aAltDataType, nsIInputStream * *_retval) +{ + LOG(("CacheEntry::OpenInputStreamInternal [this=%p]", this)); NS_ENSURE_SUCCESS(mFileStatus, NS_ERROR_NOT_AVAILABLE); @@ -1136,7 +1149,12 @@ NS_IMETHODIMP CacheEntry::OpenInputStream(int64_t offset, nsIInputStream * *_ret RefPtr selfHandle = NewHandle(); nsCOMPtr stream; - rv = mFile->OpenInputStream(selfHandle, getter_AddRefs(stream)); + if (aAltDataType) { + rv = mFile->OpenAlternativeInputStream(selfHandle, aAltDataType, + getter_AddRefs(stream)); + } else { + rv = mFile->OpenInputStream(selfHandle, getter_AddRefs(stream)); + } NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr seekable = @@ -1188,6 +1206,30 @@ NS_IMETHODIMP CacheEntry::OpenOutputStream(int64_t offset, nsIOutputStream * *_r return NS_OK; } +NS_IMETHODIMP CacheEntry::OpenAlternativeOutputStream(const nsACString & type, nsIOutputStream * *_retval) +{ + LOG(("CacheEntry::OpenAlternativeOutputStream [this=%p, type=%s]", this, + PromiseFlatCString(type).get())); + + nsresult rv; + + mozilla::MutexAutoLock lock(mLock); + + if (!mHasData || mState < READY || mOutputStream || mIsDoomed) { + LOG((" entry not in state to write alt-data")); + return NS_ERROR_NOT_AVAILABLE; + } + + nsCOMPtr stream; + rv = mFile->OpenAlternativeOutputStream(nullptr, + PromiseFlatCString(type).get(), + getter_AddRefs(stream)); + NS_ENSURE_SUCCESS(rv, rv); + + stream.swap(*_retval); + return NS_OK; +} + nsresult CacheEntry::OpenOutputStreamInternal(int64_t offset, nsIOutputStream * *_retval) { LOG(("CacheEntry::OpenOutputStreamInternal [this=%p]", this)); diff --git a/netwerk/cache2/CacheEntry.h b/netwerk/cache2/CacheEntry.h index 688a28125c17..7331be2a4f55 100644 --- a/netwerk/cache2/CacheEntry.h +++ b/netwerk/cache2/CacheEntry.h @@ -242,6 +242,7 @@ private: void OnFetched(Callback const & aCallback); nsresult OpenOutputStreamInternal(int64_t offset, nsIOutputStream * *_retval); + nsresult OpenInputStreamInternal(int64_t offset, const char *aAltDataType, nsIInputStream * *_retval); void OnHandleClosed(CacheEntryHandle const* aHandle); diff --git a/netwerk/cache2/OldWrappers.h b/netwerk/cache2/OldWrappers.h index 33c7d9b71e82..c89e3abf1b54 100644 --- a/netwerk/cache2/OldWrappers.h +++ b/netwerk/cache2/OldWrappers.h @@ -45,6 +45,15 @@ public: return !mOldDesc ? NS_ERROR_NULL_POINTER : mOldDesc->OpenOutputStream(offset, _retval); } + NS_IMETHOD OpenAlternativeOutputStream(const nsACString & type, nsIOutputStream * *_retval) override + { + return NS_ERROR_NOT_IMPLEMENTED; + } + NS_IMETHOD OpenAlternativeInputStream(const nsACString & type, nsIInputStream * *_retval) override + { + return NS_ERROR_NOT_IMPLEMENTED; + } + NS_IMETHOD GetPredictedDataSize(int64_t *aPredictedDataSize) override { return !mOldDesc ? NS_ERROR_NULL_POINTER : diff --git a/netwerk/cache2/nsICacheEntry.idl b/netwerk/cache2/nsICacheEntry.idl index 327baf450dab..a8c093b46e3f 100644 --- a/netwerk/cache2/nsICacheEntry.idl +++ b/netwerk/cache2/nsICacheEntry.idl @@ -196,6 +196,29 @@ interface nsICacheEntry : nsISupports */ readonly attribute long long dataSize; + /** + * Opens and returns an output stream that a consumer may use to save an + * alternate representation of the data. + * @throws + * - NS_ERROR_NOT_AVAILABLE if the real data hasn't been written. + * - NS_ERROR_IN_PROGRESS when the writing regular content or alt-data to + * the cache entry is still in progress. + * + * If there is alt-data already saved, it will be overwritten. + */ + nsIOutputStream openAlternativeOutputStream(in ACString type); + + /** + * Opens and returns an input stream that can be used to read the alternative + * representation previously saved in the cache. + * If this call is made while writing alt-data is still in progress, it is + * still possible to read content from the input stream as it's being written. + * @throws + * - NS_ERROR_NOT_AVAILABLE if the alt-data representation doesn't exist at + * all or if alt-data of the given type doesn't exist. + */ + nsIInputStream openAlternativeInputStream(in ACString type); + /**************************************************************************** * The following methods might be added to some nsICacheEntryInternal * interface since we want to remove them as soon as the old cache backend is diff --git a/netwerk/ipc/NeckoChannelParams.ipdlh b/netwerk/ipc/NeckoChannelParams.ipdlh index 6bc287182ed8..2b421d9efaa0 100644 --- a/netwerk/ipc/NeckoChannelParams.ipdlh +++ b/netwerk/ipc/NeckoChannelParams.ipdlh @@ -126,6 +126,7 @@ struct HttpChannelOpenArgs bool allowStaleCacheContent; nsCString contentTypeHint; nsCString channelId; + nsCString preferredAlternativeType; }; struct HttpChannelConnectArgs diff --git a/netwerk/ipc/NeckoChild.cpp b/netwerk/ipc/NeckoChild.cpp index aaf3391211f8..565c130205db 100644 --- a/netwerk/ipc/NeckoChild.cpp +++ b/netwerk/ipc/NeckoChild.cpp @@ -23,6 +23,8 @@ #include "mozilla/dom/network/TCPSocketChild.h" #include "mozilla/dom/network/TCPServerSocketChild.h" #include "mozilla/dom/network/UDPSocketChild.h" +#include "mozilla/net/AltDataOutputStreamChild.h" + #ifdef NECKO_PROTOCOL_rtsp #include "mozilla/net/RtspControllerChild.h" #include "mozilla/net/RtspChannelChild.h" @@ -88,6 +90,24 @@ NeckoChild::DeallocPHttpChannelChild(PHttpChannelChild* channel) return true; } +PAltDataOutputStreamChild* +NeckoChild::AllocPAltDataOutputStreamChild( + const nsCString& type, + PHttpChannelChild* channel) +{ + AltDataOutputStreamChild* stream = new AltDataOutputStreamChild(); + stream->AddIPDLReference(); + return stream; +} + +bool +NeckoChild::DeallocPAltDataOutputStreamChild(PAltDataOutputStreamChild* aActor) +{ + AltDataOutputStreamChild* child = static_cast(aActor); + child->ReleaseIPDLReference(); + return true; +} + PFTPChannelChild* NeckoChild::AllocPFTPChannelChild(const PBrowserOrId& aBrowser, const SerializedLoadContext& aSerialized, diff --git a/netwerk/ipc/NeckoChild.h b/netwerk/ipc/NeckoChild.h index d246e5d00410..4dfa13fb6fb7 100644 --- a/netwerk/ipc/NeckoChild.h +++ b/netwerk/ipc/NeckoChild.h @@ -29,6 +29,10 @@ protected: AllocPHttpChannelChild(const PBrowserOrId&, const SerializedLoadContext&, const HttpChannelCreationArgs& aOpenArgs) override; virtual bool DeallocPHttpChannelChild(PHttpChannelChild*) override; + + virtual PAltDataOutputStreamChild* AllocPAltDataOutputStreamChild(const nsCString& type, PHttpChannelChild* channel) override; + virtual bool DeallocPAltDataOutputStreamChild(PAltDataOutputStreamChild* aActor) override; + virtual PCookieServiceChild* AllocPCookieServiceChild() override; virtual bool DeallocPCookieServiceChild(PCookieServiceChild*) override; virtual PWyciwygChannelChild* AllocPWyciwygChannelChild() override; diff --git a/netwerk/ipc/NeckoParent.cpp b/netwerk/ipc/NeckoParent.cpp index 40cd99334069..ce4ad8bd1326 100644 --- a/netwerk/ipc/NeckoParent.cpp +++ b/netwerk/ipc/NeckoParent.cpp @@ -15,6 +15,8 @@ #include "mozilla/net/WebSocketChannelParent.h" #include "mozilla/net/WebSocketEventListenerParent.h" #include "mozilla/net/DataChannelParent.h" +#include "mozilla/net/AltDataOutputStreamParent.h" +#include "mozilla/Unused.h" #ifdef NECKO_PROTOCOL_rtsp #include "mozilla/net/RtspControllerParent.h" #include "mozilla/net/RtspChannelParent.h" @@ -257,6 +259,30 @@ NeckoParent::RecvPHttpChannelConstructor( return p->Init(aOpenArgs); } +PAltDataOutputStreamParent* +NeckoParent::AllocPAltDataOutputStreamParent( + const nsCString& type, + PHttpChannelParent* channel) +{ + HttpChannelParent* chan = static_cast(channel); + nsCOMPtr stream; + nsresult rv = chan->OpenAlternativeOutputStream(type, getter_AddRefs(stream)); + AltDataOutputStreamParent* parent = new AltDataOutputStreamParent(stream); + parent->AddRef(); + // If the return value was not NS_OK, the error code will be sent + // asynchronously to the child, after receiving the first message. + parent->SetError(rv); + return parent; +} + +bool +NeckoParent::DeallocPAltDataOutputStreamParent(PAltDataOutputStreamParent* aActor) +{ + AltDataOutputStreamParent* parent = static_cast(aActor); + parent->Release(); + return true; +} + PFTPChannelParent* NeckoParent::AllocPFTPChannelParent(const PBrowserOrId& aBrowser, const SerializedLoadContext& aSerialized, diff --git a/netwerk/ipc/NeckoParent.h b/netwerk/ipc/NeckoParent.h index 6dbd35e7d92f..737fd96fb107 100644 --- a/netwerk/ipc/NeckoParent.h +++ b/netwerk/ipc/NeckoParent.h @@ -105,6 +105,12 @@ protected: const SerializedLoadContext& aSerialized, const HttpChannelCreationArgs& aOpenArgs) override; virtual bool DeallocPHttpChannelParent(PHttpChannelParent*) override; + + virtual PAltDataOutputStreamParent* AllocPAltDataOutputStreamParent( + const nsCString& type, PHttpChannelParent* channel) override; + virtual bool DeallocPAltDataOutputStreamParent( + PAltDataOutputStreamParent* aActor) override; + virtual bool DeallocPCookieServiceParent(PCookieServiceParent*) override; virtual PWyciwygChannelParent* AllocPWyciwygChannelParent() override; virtual bool DeallocPWyciwygChannelParent(PWyciwygChannelParent*) override; diff --git a/netwerk/ipc/PNecko.ipdl b/netwerk/ipc/PNecko.ipdl index bc0bfbd52c5e..29d049610abf 100644 --- a/netwerk/ipc/PNecko.ipdl +++ b/netwerk/ipc/PNecko.ipdl @@ -30,6 +30,7 @@ include URIParams; include InputStreamParams; include NeckoChannelParams; include PBrowserOrId; +include protocol PAltDataOutputStream; using class IPC::SerializedLoadContext from "SerializedLoadContext.h"; using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h"; @@ -58,6 +59,7 @@ prio(normal upto urgent) sync protocol PNecko manages PRtspChannel; manages PChannelDiverter; manages PTransportProvider; + manages PAltDataOutputStream; parent: async __delete__(); @@ -116,6 +118,8 @@ parent: async RemoveRequestContext(nsCString rcid); + async PAltDataOutputStream(nsCString type, PHttpChannel channel); + child: /* * Bring up the http auth prompt for a nested remote mozbrowser. diff --git a/netwerk/protocol/http/AltDataOutputStreamChild.cpp b/netwerk/protocol/http/AltDataOutputStreamChild.cpp new file mode 100644 index 000000000000..b24514685e51 --- /dev/null +++ b/netwerk/protocol/http/AltDataOutputStreamChild.cpp @@ -0,0 +1,151 @@ +#include "mozilla/net/AltDataOutputStreamChild.h" +#include "mozilla/Unused.h" +#include "nsIInputStream.h" + +namespace mozilla { +namespace net { + +NS_IMPL_ADDREF(AltDataOutputStreamChild) + +NS_IMETHODIMP_(MozExternalRefCountType) AltDataOutputStreamChild::Release() +{ + NS_PRECONDITION(0 != mRefCnt, "dup release"); + MOZ_ASSERT(NS_IsMainThread(), "Main thread only"); + --mRefCnt; + NS_LOG_RELEASE(this, mRefCnt, "AltDataOutputStreamChild"); + + if (mRefCnt == 1 && mIPCOpen) { + // Send_delete calls NeckoChild::PAltDataOutputStreamChild, which will release + // again to refcount == 0 + PAltDataOutputStreamChild::Send__delete__(this); + return 0; + } + + if (mRefCnt == 0) { + mRefCnt = 1; /* stabilize */ + delete this; + return 0; + } + return mRefCnt; +} + +NS_INTERFACE_MAP_BEGIN(AltDataOutputStreamChild) + NS_INTERFACE_MAP_ENTRY(nsIOutputStream) + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +AltDataOutputStreamChild::AltDataOutputStreamChild() + : mIPCOpen(false) + , mError(NS_OK) +{ + MOZ_ASSERT(NS_IsMainThread(), "Main thread only"); +} + +AltDataOutputStreamChild::~AltDataOutputStreamChild() +{ +} + +void +AltDataOutputStreamChild::AddIPDLReference() +{ + MOZ_ASSERT(!mIPCOpen, "Attempt to retain more than one IPDL reference"); + mIPCOpen = true; + AddRef(); +} + +void +AltDataOutputStreamChild::ReleaseIPDLReference() +{ + MOZ_ASSERT(mIPCOpen, "Attempt to release nonexistent IPDL reference"); + mIPCOpen = false; + Release(); +} + +bool +AltDataOutputStreamChild::WriteDataInChunks(const nsCString& data) +{ + const uint32_t kChunkSize = 128*1024; + uint32_t next = std::min(data.Length(), kChunkSize); + for (uint32_t i = 0; i < data.Length(); + i = next, next = std::min(data.Length(), next + kChunkSize)) { + nsCString chunk(Substring(data, i, kChunkSize)); + if (mIPCOpen && !SendWriteData(chunk)) { + mIPCOpen = false; + return false; + } + } + return true; +} + +NS_IMETHODIMP +AltDataOutputStreamChild::Close() +{ + if (!mIPCOpen) { + return NS_ERROR_NOT_AVAILABLE; + } + if (NS_FAILED(mError)) { + return mError; + } + Unused << SendClose(); + return NS_OK; +} + +NS_IMETHODIMP +AltDataOutputStreamChild::Flush() +{ + if (!mIPCOpen) { + return NS_ERROR_NOT_AVAILABLE; + } + if (NS_FAILED(mError)) { + return mError; + } + + // This is a no-op + return NS_OK; +} + +NS_IMETHODIMP +AltDataOutputStreamChild::Write(const char * aBuf, uint32_t aCount, uint32_t *_retval) +{ + if (!mIPCOpen) { + return NS_ERROR_NOT_AVAILABLE; + } + if (NS_FAILED(mError)) { + return mError; + } + if (WriteDataInChunks(nsCString(aBuf, aCount))) { + *_retval = aCount; + return NS_OK; + } + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +AltDataOutputStreamChild::WriteFrom(nsIInputStream *aFromStream, uint32_t aCount, uint32_t *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +AltDataOutputStreamChild::WriteSegments(nsReadSegmentFun aReader, void *aClosure, uint32_t aCount, uint32_t *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +AltDataOutputStreamChild::IsNonBlocking(bool *_retval) +{ + *_retval = false; + return NS_OK; +} + +bool +AltDataOutputStreamChild::RecvError(const nsresult& err) +{ + mError = err; + return true; +} + + +} // namespace net +} // namespace mozilla diff --git a/netwerk/protocol/http/AltDataOutputStreamChild.h b/netwerk/protocol/http/AltDataOutputStreamChild.h new file mode 100644 index 000000000000..76b4b82ba19f --- /dev/null +++ b/netwerk/protocol/http/AltDataOutputStreamChild.h @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et tw=80 : */ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_net_AltDataOutputStreamChild_h +#define mozilla_net_AltDataOutputStreamChild_h + +#include "mozilla/net/PAltDataOutputStreamChild.h" +#include "nsIOutputStream.h" + +namespace mozilla { +namespace net { + +class AltDataOutputStreamChild + : public PAltDataOutputStreamChild + , public nsIOutputStream +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIOUTPUTSTREAM + explicit AltDataOutputStreamChild(); + + void AddIPDLReference(); + void ReleaseIPDLReference(); + // Saves an error code which will be reported to the writer on the next call. + virtual bool RecvError(const nsresult& err) override; + +private: + virtual ~AltDataOutputStreamChild(); + // Sends data to the parent process in 256k chunks. + bool WriteDataInChunks(const nsCString& data); + + bool mIPCOpen; + // If there was an error opening the output stream or writing to it on the + // parent side, this will be set to the error code. We check it before we + // write so we can report an error to the consumer. + nsresult mError; +}; + +} // namespace net +} // namespace mozilla + +#endif // mozilla_net_AltDataOutputStreamChild_h diff --git a/netwerk/protocol/http/AltDataOutputStreamParent.cpp b/netwerk/protocol/http/AltDataOutputStreamParent.cpp new file mode 100644 index 000000000000..1181209dc70b --- /dev/null +++ b/netwerk/protocol/http/AltDataOutputStreamParent.cpp @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et tw=80 : */ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/net/AltDataOutputStreamParent.h" +#include "mozilla/Unused.h" + +namespace mozilla { +namespace net { + +NS_IMPL_ISUPPORTS0(AltDataOutputStreamParent) + +AltDataOutputStreamParent::AltDataOutputStreamParent(nsIOutputStream* aStream) + : mOutputStream(aStream) + , mStatus(NS_OK) +{ + MOZ_ASSERT(NS_IsMainThread(), "Main thread only"); +} + +AltDataOutputStreamParent::~AltDataOutputStreamParent() +{ + MOZ_ASSERT(NS_IsMainThread(), "Main thread only"); +} + +bool +AltDataOutputStreamParent::RecvWriteData(const nsCString& data) +{ + if (NS_FAILED(mStatus)) { + Unused << SendError(mStatus); + return true; + } + nsresult rv; + uint32_t n; + if (mOutputStream) { + rv = mOutputStream->Write(data.BeginReading(), data.Length(), &n); + MOZ_ASSERT(n == data.Length()); + if (NS_FAILED(rv)) { + Unused << SendError(rv); + } + } + return true; +} + +bool +AltDataOutputStreamParent::RecvClose() +{ + if (NS_FAILED(mStatus)) { + Unused << SendError(mStatus); + return true; + } + nsresult rv; + if (mOutputStream) { + rv = mOutputStream->Close(); + if (NS_FAILED(rv)) { + Unused << SendError(rv); + } + mOutputStream = nullptr; + } + return true; +} + +void +AltDataOutputStreamParent::ActorDestroy(ActorDestroyReason aWhy) +{ +} + +} // namespace net +} // namespace mozilla diff --git a/netwerk/protocol/http/AltDataOutputStreamParent.h b/netwerk/protocol/http/AltDataOutputStreamParent.h new file mode 100644 index 000000000000..208339efb904 --- /dev/null +++ b/netwerk/protocol/http/AltDataOutputStreamParent.h @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et tw=80 : */ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_net_AltDataOutputStreamParent_h +#define mozilla_net_AltDataOutputStreamParent_h + +#include "mozilla/net/PAltDataOutputStreamParent.h" +#include "nsIOutputStream.h" + +namespace mozilla { +namespace net { + +// Forwards data received from the content process to an output stream. +class AltDataOutputStreamParent + : public PAltDataOutputStreamParent + , public nsISupports +{ +public: + NS_DECL_ISUPPORTS + + // Called from NeckoParent::AllocPAltDataOutputStreamParent which also opens + // the output stream. + // aStream may be null + explicit AltDataOutputStreamParent(nsIOutputStream* aStream); + + // Called when data is received from the content process. + // We proceed to write that data to the output stream. + virtual bool RecvWriteData(const nsCString& data) override; + // Called when AltDataOutputStreamChild::Close() is + // Closes and nulls the output stream. + virtual bool RecvClose() override; + virtual void ActorDestroy(ActorDestroyReason aWhy) override; + + // Sets an error that will be reported to the content process. + void SetError(nsresult status) { mStatus = status; } + +private: + virtual ~AltDataOutputStreamParent(); + nsCOMPtr mOutputStream; + // In case any error occurs mStatus will be != NS_OK, and this status code will + // be sent to the content process asynchronously. + nsresult mStatus; +}; + +} // namespace net +} // namespace mozilla + +#endif // mozilla_net_AltDataOutputStreamParent_h diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp index c40c74d7ec7d..049fe8f057ab 100644 --- a/netwerk/protocol/http/HttpBaseChannel.cpp +++ b/netwerk/protocol/http/HttpBaseChannel.cpp @@ -54,6 +54,7 @@ #include "mozilla/BinarySearch.h" #include "nsIHttpHeaderVisitor.h" #include "nsIXULRuntime.h" +#include "nsICacheInfoChannel.h" #include @@ -107,6 +108,7 @@ HttpBaseChannel::HttpBaseChannel() , mFetchCacheMode(nsIHttpChannelInternal::FETCH_CACHE_MODE_DEFAULT) , mOnStartRequestCalled(false) , mOnStopRequestCalled(false) + , mAfterOnStartRequestBegun(false) , mTransferSize(0) , mDecodedBodySize(0) , mEncodedBodySize(0) @@ -924,6 +926,11 @@ HttpBaseChannel::DoApplyContentConversions(nsIStreamListener* aNextListener, return NS_OK; } + if (!mAvailableCachedAltDataType.IsEmpty()) { + LOG(("not applying conversion because delivering alt-data\n")); + return NS_OK; + } + nsAutoCString contentEncoding; nsresult rv = mResponseHead->GetHeader(nsHttp::Content_Encoding, contentEncoding); if (NS_FAILED(rv) || contentEncoding.IsEmpty()) @@ -3161,6 +3168,12 @@ HttpBaseChannel::SetupReplacementChannel(nsIURI *newURI, } } + // Pass the preferred alt-data type on to the new channel. + nsCOMPtr cacheInfoChan(do_QueryInterface(newChannel)); + if (cacheInfoChan) { + cacheInfoChan->PreferAlternativeDataType(mPreferredCachedAltDataType); + } + if (redirectFlags & (nsIChannelEventSink::REDIRECT_INTERNAL | nsIChannelEventSink::REDIRECT_STS_UPGRADE)) { // Copy non-origin related headers to the new channel. diff --git a/netwerk/protocol/http/HttpBaseChannel.h b/netwerk/protocol/http/HttpBaseChannel.h index bda22e734bad..004c22c9803e 100644 --- a/netwerk/protocol/http/HttpBaseChannel.h +++ b/netwerk/protocol/http/HttpBaseChannel.h @@ -530,6 +530,10 @@ protected: bool mOnStartRequestCalled; bool mOnStopRequestCalled; + // Defaults to false. Is set to true at the begining of OnStartRequest. + // Used to ensure methods can't be called before OnStartRequest. + bool mAfterOnStartRequestBegun; + uint64_t mTransferSize; uint64_t mDecodedBodySize; uint64_t mEncodedBodySize; @@ -545,6 +549,11 @@ protected: nsCOMPtr mReportCollector; + // Holds the name of the preferred alt-data type. + nsCString mPreferredCachedAltDataType; + // Holds the name of the alternative data type the channel returned. + nsCString mAvailableCachedAltDataType; + bool mForceMainDocumentChannel; nsID mChannelId; diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp index 6141a6377b65..9ffc84e9f224 100644 --- a/netwerk/protocol/http/HttpChannelChild.cpp +++ b/netwerk/protocol/http/HttpChannelChild.cpp @@ -314,7 +314,8 @@ class StartRequestEvent : public ChannelEvent const nsCString& aSecurityInfoSerialization, const NetAddr& aSelfAddr, const NetAddr& aPeerAddr, - const uint32_t& aCacheKey) + const uint32_t& aCacheKey, + const nsCString& altDataType) : mChild(aChild) , mChannelStatus(aChannelStatus) , mResponseHead(aResponseHead) @@ -328,6 +329,7 @@ class StartRequestEvent : public ChannelEvent , mSelfAddr(aSelfAddr) , mPeerAddr(aPeerAddr) , mCacheKey(aCacheKey) + , mAltDataType(altDataType) {} void Run() @@ -337,7 +339,7 @@ class StartRequestEvent : public ChannelEvent mRequestHeaders, mIsFromCache, mCacheEntryAvailable, mCacheExpirationTime, mCachedCharset, mSecurityInfoSerialization, mSelfAddr, mPeerAddr, - mCacheKey); + mCacheKey, mAltDataType); } private: HttpChannelChild* mChild; @@ -353,6 +355,7 @@ class StartRequestEvent : public ChannelEvent NetAddr mSelfAddr; NetAddr mPeerAddr; uint32_t mCacheKey; + nsCString mAltDataType; }; bool @@ -368,7 +371,8 @@ HttpChannelChild::RecvOnStartRequest(const nsresult& channelStatus, const NetAddr& selfAddr, const NetAddr& peerAddr, const int16_t& redirectCount, - const uint32_t& cacheKey) + const uint32_t& cacheKey, + const nsCString& altDataType) { LOG(("HttpChannelChild::RecvOnStartRequest [this=%p]\n", this)); // mFlushedForDiversion and mDivertingToParent should NEVER be set at this @@ -387,7 +391,8 @@ HttpChannelChild::RecvOnStartRequest(const nsresult& channelStatus, cacheExpirationTime, cachedCharset, securityInfoSerialization, - selfAddr, peerAddr, cacheKey)); + selfAddr, peerAddr, cacheKey, + altDataType)); return true; } @@ -403,7 +408,8 @@ HttpChannelChild::OnStartRequest(const nsresult& channelStatus, const nsCString& securityInfoSerialization, const NetAddr& selfAddr, const NetAddr& peerAddr, - const uint32_t& cacheKey) + const uint32_t& cacheKey, + const nsCString& altDataType) { LOG(("HttpChannelChild::OnStartRequest [this=%p]\n", this)); @@ -433,6 +439,10 @@ HttpChannelChild::OnStartRequest(const nsresult& channelStatus, mSelfAddr = selfAddr; mPeerAddr = peerAddr; + mAvailableCachedAltDataType = altDataType; + + mAfterOnStartRequestBegun = true; + AutoEventEnqueuer ensureSerialDispatch(mEventQ); nsresult rv; @@ -913,6 +923,13 @@ HttpChannelChild::OnStopRequest(const nsresult& channelStatus, ReleaseListeners(); + // DocumentChannelCleanup actually nulls out mCacheEntry in the parent, which + // we might need later to open the Alt-Data output stream, so just return here + if (!mPreferredCachedAltDataType.IsEmpty()) { + mKeptAlive = true; + return; + } + if (mLoadFlags & LOAD_DOCUMENT_URI) { // Keep IPDL channel open, but only for updating security info. mKeptAlive = true; @@ -1905,6 +1922,7 @@ HttpChannelChild::ContinueAsyncOpen() openArgs.loadFlags() = mLoadFlags; openArgs.requestHeaders() = mClientSetRequestHeaders; mRequestHead.Method(openArgs.requestMethod()); + openArgs.preferredAlternativeType() = mPreferredCachedAltDataType; nsTArray fds; SerializeInputStream(mUploadStream, openArgs.uploadStream(), fds); @@ -2178,6 +2196,36 @@ HttpChannelChild::GetAllowStaleCacheContent(bool *aAllowStaleCacheContent) return NS_OK; } +NS_IMETHODIMP +HttpChannelChild::PreferAlternativeDataType(const nsACString & aType) +{ + ENSURE_CALLED_BEFORE_ASYNC_OPEN(); + mPreferredCachedAltDataType = aType; + return NS_OK; +} + +NS_IMETHODIMP +HttpChannelChild::GetAlternativeDataType(nsACString & aType) +{ + // Must be called during or after OnStartRequest + if (!mAfterOnStartRequestBegun) { + return NS_ERROR_NOT_AVAILABLE; + } + + aType = mAvailableCachedAltDataType; + return NS_OK; +} + +NS_IMETHODIMP +HttpChannelChild::OpenAlternativeOutputStream(const nsACString & aType, nsIOutputStream * *_retval) +{ + MOZ_ASSERT(NS_IsMainThread(), "Main thread only"); + RefPtr stream = + static_cast(gNeckoChild->SendPAltDataOutputStreamConstructor(nsCString(aType), this)); + stream.forget(_retval); + return NS_OK; +} + //----------------------------------------------------------------------------- // HttpChannelChild::nsIResumableChannel //----------------------------------------------------------------------------- diff --git a/netwerk/protocol/http/HttpChannelChild.h b/netwerk/protocol/http/HttpChannelChild.h index 3dabad5ae9d3..df46dd6a5fd5 100644 --- a/netwerk/protocol/http/HttpChannelChild.h +++ b/netwerk/protocol/http/HttpChannelChild.h @@ -121,7 +121,8 @@ protected: const NetAddr& selfAddr, const NetAddr& peerAddr, const int16_t& redirectCount, - const uint32_t& cacheKey) override; + const uint32_t& cacheKey, + const nsCString& altDataType) override; bool RecvOnTransportAndData(const nsresult& channelStatus, const nsresult& status, const uint64_t& progress, @@ -261,7 +262,8 @@ private: const nsCString& securityInfoSerialization, const NetAddr& selfAddr, const NetAddr& peerAddr, - const uint32_t& cacheKey); + const uint32_t& cacheKey, + const nsCString& altDataType); void MaybeDivertOnData(const nsCString& data, const uint64_t& offset, const uint32_t& count); diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp index d07793f99fa2..78a92fe15531 100644 --- a/netwerk/protocol/http/HttpChannelParent.cpp +++ b/netwerk/protocol/http/HttpChannelParent.cpp @@ -134,7 +134,7 @@ HttpChannelParent::Init(const HttpChannelCreationArgs& aArgs) a.initialRwin(), a.blockAuthPrompt(), a.suspendAfterSynthesizeResponse(), a.allowStaleCacheContent(), a.contentTypeHint(), - a.channelId()); + a.channelId(), a.preferredAlternativeType()); } case HttpChannelCreationArgs::THttpChannelConnectArgs: { @@ -266,7 +266,8 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI, const bool& aSuspendAfterSynthesizeResponse, const bool& aAllowStaleCacheContent, const nsCString& aContentTypeHint, - const nsCString& aChannelId) + const nsCString& aChannelId, + const nsCString& aPreferredAlternativeType) { nsCOMPtr uri = DeserializeURI(aURI); if (!uri) { @@ -421,6 +422,7 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI, } mChannel->SetCacheKey(cacheKey); + mChannel->PreferAlternativeDataType(aPreferredAlternativeType); mChannel->SetAllowStaleCacheContent(aAllowStaleCacheContent); @@ -1059,6 +1061,9 @@ HttpChannelParent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) } } + nsAutoCString altDataType; + mChannel->GetAlternativeDataType(altDataType); + // !!! We need to lock headers and please don't forget to unlock them !!! requestHead->Enter(); nsresult rv = NS_OK; @@ -1072,7 +1077,8 @@ HttpChannelParent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) expirationTime, cachedCharset, secInfoSerialization, mChannel->GetSelfAddr(), mChannel->GetPeerAddr(), redirectCount, - cacheKeyValue)) + cacheKeyValue, + altDataType)) { rv = NS_ERROR_UNEXPECTED; } @@ -1592,6 +1598,17 @@ HttpChannelParent::NotifyDiversionFailed(nsresult aErrorCode, } } +nsresult +HttpChannelParent::OpenAlternativeOutputStream(const nsACString & type, nsIOutputStream * *_retval) +{ + // We need to make sure the child does not call SendDocumentChannelCleanup() + // before opening the altOutputStream, because that clears mCacheEntry. + if (!mCacheEntry) { + return NS_ERROR_NOT_AVAILABLE; + } + return mCacheEntry->OpenAlternativeOutputStream(type, _retval); +} + void HttpChannelParent::OfflineDisconnect() { diff --git a/netwerk/protocol/http/HttpChannelParent.h b/netwerk/protocol/http/HttpChannelParent.h index 9eb5e0c754e9..4232517ff13f 100644 --- a/netwerk/protocol/http/HttpChannelParent.h +++ b/netwerk/protocol/http/HttpChannelParent.h @@ -98,6 +98,8 @@ public: } } + nsresult OpenAlternativeOutputStream(const nsACString & type, nsIOutputStream * *_retval); + protected: // used to connect redirected-to channel in parent with just created // ChildChannel. Used during redirects. @@ -140,7 +142,8 @@ protected: const bool& aSuspendAfterSynthesizeResponse, const bool& aAllowStaleCacheContent, const nsCString& aContentTypeHint, - const nsCString& aChannelId); + const nsCString& aChannelId, + const nsCString& aPreferredAlternativeType); virtual bool RecvSetPriority(const uint16_t& priority) override; virtual bool RecvSetClassOfService(const uint32_t& cos) override; diff --git a/netwerk/protocol/http/PAltDataOutputStream.ipdl b/netwerk/protocol/http/PAltDataOutputStream.ipdl new file mode 100644 index 000000000000..824137f8e33b --- /dev/null +++ b/netwerk/protocol/http/PAltDataOutputStream.ipdl @@ -0,0 +1,32 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +include protocol PNecko; + +namespace mozilla { +namespace net { + +protocol PAltDataOutputStream +{ + manager PNecko; + +parent: + // Sends data from the child to the parent that will be written to the cache. + async WriteData(nsCString data); + // Signals that writing to the output stream is done. + async Close(); + async __delete__(); + +child: + // The parent calls this method to signal that an error has ocurred. + // This may mean that opening the output stream has failed or that writing to + // the stream has returned an error. + async Error(nsresult err); +}; + +} // namespace net +} // namespace mozilla diff --git a/netwerk/protocol/http/PHttpChannel.ipdl b/netwerk/protocol/http/PHttpChannel.ipdl index e7312fb40a98..d7c0da64ac6f 100644 --- a/netwerk/protocol/http/PHttpChannel.ipdl +++ b/netwerk/protocol/http/PHttpChannel.ipdl @@ -99,7 +99,8 @@ child: NetAddr selfAddr, NetAddr peerAddr, int16_t redirectCount, - uint32_t cacheKey); + uint32_t cacheKey, + nsCString altDataType); // Combines a single OnDataAvailable and its associated OnProgress & // OnStatus calls into one IPDL message diff --git a/netwerk/protocol/http/moz.build b/netwerk/protocol/http/moz.build index 3e342be23195..467cdfde22ba 100644 --- a/netwerk/protocol/http/moz.build +++ b/netwerk/protocol/http/moz.build @@ -31,6 +31,8 @@ EXPORTS += [ ] EXPORTS.mozilla.net += [ + 'AltDataOutputStreamChild.h', + 'AltDataOutputStreamParent.h', 'HttpBaseChannel.h', 'HttpChannelChild.h', 'HttpChannelParent.h', @@ -53,6 +55,8 @@ SOURCES += [ ] UNIFIED_SOURCES += [ + 'AltDataOutputStreamChild.cpp', + 'AltDataOutputStreamParent.cpp', 'CacheControlParser.cpp', 'ConnectionDiagnostics.cpp', 'Http2Compression.cpp', @@ -95,6 +99,7 @@ SOURCES += [ ] IPDL_SOURCES += [ + 'PAltDataOutputStream.ipdl', 'PHttpChannel.ipdl', ] diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index 5d7d7a400834..5dbe0b6dff5f 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -466,7 +466,7 @@ nsHttpChannel::ContinueConnect() if (!mFallbackChannel && !mFallbackKey.IsEmpty()) { return AsyncCall(&nsHttpChannel::HandleAsyncFallback); } - LOG((" !mCachedEntry && mLoadFlags & LOAD_ONLY_FROM_CACHE")); + LOG((" !mCacheEntry && mLoadFlags & LOAD_ONLY_FROM_CACHE")); return NS_ERROR_DOCUMENT_NOT_CACHED; } @@ -4496,7 +4496,24 @@ nsHttpChannel::OpenCacheInputStream(nsICacheEntry* cacheEntry, bool startBufferi // Open an input stream for the entity, so that the call to OpenInputStream // happens off the main thread. nsCOMPtr stream; - rv = cacheEntry->OpenInputStream(0, getter_AddRefs(stream)); + + // If an alternate representation was requested, try to open the alt + // input stream. + if (!mPreferredCachedAltDataType.IsEmpty()) { + rv = cacheEntry->OpenAlternativeInputStream(mPreferredCachedAltDataType, + getter_AddRefs(stream)); + if (NS_SUCCEEDED(rv)) { + // We have succeeded. + mAvailableCachedAltDataType = mPreferredCachedAltDataType; + // The alternative data may have a different length than the original + // content, so we clear the Content-Length header + mCachedResponseHead->SetContentLength(-1); + } + } + + if (!stream) { + rv = cacheEntry->OpenInputStream(0, getter_AddRefs(stream)); + } if (NS_FAILED(rv)) { LOG(("Failed to open cache input stream [channel=%p, " @@ -6340,6 +6357,8 @@ nsHttpChannel::OnStartRequest(nsIRequest *request, nsISupports *ctxt) MOZ_ASSERT(!(mTransactionPump && mCachePump) || mCachedContentIsPartial, "If we have both pumps, the cache content must be partial"); + mAfterOnStartRequestBegun = true; + if (!mSecurityInfo && !mCachePump && mTransaction) { // grab the security info from the connection object; the transaction // is guaranteed to own a reference to the connection. @@ -6689,6 +6708,14 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult st mOnStopRequestCalled = true; } + // If a preferred alt-data type was set, this signals the consumer is + // interested in reading and/or writing the alt-data representation. + // We need to hold a reference to the cache entry in case the listener calls + // openAlternativeOutputStream() after CloseCacheEntry() clears mCacheEntry. + if (!mPreferredCachedAltDataType.IsEmpty()) { + mAltDataCacheEntry = mCacheEntry; + } + CloseCacheEntry(!contentComplete); if (mOfflineCacheEntry) @@ -7052,6 +7079,37 @@ nsHttpChannel::GetAllowStaleCacheContent(bool *aAllowStaleCacheContent) return NS_OK; } +NS_IMETHODIMP +nsHttpChannel::PreferAlternativeDataType(const nsACString & aType) +{ + ENSURE_CALLED_BEFORE_ASYNC_OPEN(); + mPreferredCachedAltDataType = aType; + return NS_OK; +} + +NS_IMETHODIMP +nsHttpChannel::GetAlternativeDataType(nsACString & aType) +{ + // must be called during or after OnStartRequest + if (!mAfterOnStartRequestBegun) { + return NS_ERROR_NOT_AVAILABLE; + } + aType = mAvailableCachedAltDataType; + return NS_OK; +} + +NS_IMETHODIMP +nsHttpChannel::OpenAlternativeOutputStream(const nsACString & type, nsIOutputStream * *_retval) +{ + // OnStopRequest will clear mCacheEntry, but we may use mAltDataCacheEntry + // if the consumer called PreferAlternativeDataType() + nsCOMPtr cacheEntry = mCacheEntry ? mCacheEntry : mAltDataCacheEntry; + if (!cacheEntry) { + return NS_ERROR_NOT_AVAILABLE; + } + return cacheEntry->OpenAlternativeOutputStream(type, _retval); +} + //----------------------------------------------------------------------------- // nsHttpChannel::nsICachingChannel //----------------------------------------------------------------------------- diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h index 37517b4fba57..d5fa26c00daf 100644 --- a/netwerk/protocol/http/nsHttpChannel.h +++ b/netwerk/protocol/http/nsHttpChannel.h @@ -457,6 +457,12 @@ private: // cache specific data nsCOMPtr mCacheEntry; + // This will be set during OnStopRequest() before calling CloseCacheEntry(), + // but only if the listener wants to use alt-data (signaled by + // HttpBaseChannel::mPreferredCachedAltDataType being not empty) + // Needed because calling openAlternativeOutputStream needs a reference + // to the cache entry. + nsCOMPtr mAltDataCacheEntry; // We must close mCacheInputStream explicitly to avoid leaks. AutoClose mCacheInputStream; RefPtr mCachePump; From 29eff7dfe4edede3c68fdc1f43341d2e4b4f1320 Mon Sep 17 00:00:00 2001 From: Valentin Gosu Date: Tue, 27 Sep 2016 10:26:00 +0200 Subject: [PATCH 015/102] Bug 1231565 - (Part 3) Make alt-data responses report the correct content length r=michal MozReview-Commit-ID: DvQP7NB4SqW --- netwerk/cache2/CacheEntry.cpp | 11 +++++++++++ netwerk/cache2/CacheFile.cpp | 16 ++++++++++++++++ netwerk/cache2/CacheFile.h | 2 ++ netwerk/cache2/OldWrappers.cpp | 5 +++++ netwerk/cache2/OldWrappers.h | 1 + netwerk/cache2/nsICacheEntry.idl | 9 +++++++++ netwerk/protocol/http/nsHttpChannel.cpp | 8 ++++++-- netwerk/test/unit/test_alt-data_simple.js | 2 +- 8 files changed, 51 insertions(+), 3 deletions(-) diff --git a/netwerk/cache2/CacheEntry.cpp b/netwerk/cache2/CacheEntry.cpp index 1122fe3fc142..0ed49ef16401 100644 --- a/netwerk/cache2/CacheEntry.cpp +++ b/netwerk/cache2/CacheEntry.cpp @@ -1506,6 +1506,17 @@ NS_IMETHODIMP CacheEntry::GetDataSize(int64_t *aDataSize) return NS_OK; } + +NS_IMETHODIMP CacheEntry::GetAltDataSize(int64_t *aDataSize) +{ + LOG(("CacheEntry::GetAltDataSize [this=%p]", this)); + if (NS_FAILED(mFileStatus)) { + return mFileStatus; + } + return mFile->GetAltDataSize(aDataSize); +} + + NS_IMETHODIMP CacheEntry::MarkValid() { // NOT IMPLEMENTED ACTUALLY diff --git a/netwerk/cache2/CacheFile.cpp b/netwerk/cache2/CacheFile.cpp index 45bbcd7fbcd3..3b87ea649e1d 100644 --- a/netwerk/cache2/CacheFile.cpp +++ b/netwerk/cache2/CacheFile.cpp @@ -2100,6 +2100,22 @@ CacheFile::DataSize(int64_t* aSize) return true; } +nsresult +CacheFile::GetAltDataSize(int64_t *aSize) +{ + CacheFileAutoLock lock(this); + if (mOutput) { + return NS_ERROR_IN_PROGRESS; + } + + if (mAltDataOffset == -1) { + return NS_ERROR_NOT_AVAILABLE; + } + + *aSize = mDataSize - mAltDataOffset; + return NS_OK; +} + bool CacheFile::IsDoomed() { diff --git a/netwerk/cache2/CacheFile.h b/netwerk/cache2/CacheFile.h index cbc050f452d3..839f63cff582 100644 --- a/netwerk/cache2/CacheFile.h +++ b/netwerk/cache2/CacheFile.h @@ -91,6 +91,8 @@ public: void Kill() { mKill = true; } nsresult ThrowMemoryCachedData(); + nsresult GetAltDataSize(int64_t *aSize); + // metadata forwarders nsresult GetElement(const char *aKey, char **_retval); nsresult SetElement(const char *aKey, const char *aValue); diff --git a/netwerk/cache2/OldWrappers.cpp b/netwerk/cache2/OldWrappers.cpp index bdda4f93a715..81df88df0e8f 100644 --- a/netwerk/cache2/OldWrappers.cpp +++ b/netwerk/cache2/OldWrappers.cpp @@ -399,6 +399,11 @@ NS_IMETHODIMP _OldCacheEntryWrapper::GetDataSize(int64_t *aSize) return NS_OK; } +NS_IMETHODIMP _OldCacheEntryWrapper::GetAltDataSize(int64_t *aSize) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + NS_IMETHODIMP _OldCacheEntryWrapper::GetPersistent(bool *aPersistToDisk) { if (!mOldDesc) { diff --git a/netwerk/cache2/OldWrappers.h b/netwerk/cache2/OldWrappers.h index c89e3abf1b54..460aa0162ef8 100644 --- a/netwerk/cache2/OldWrappers.h +++ b/netwerk/cache2/OldWrappers.h @@ -139,6 +139,7 @@ public: NS_IMETHOD MetaDataReady() override { return NS_OK; } NS_IMETHOD Recreate(bool, nsICacheEntry**) override; NS_IMETHOD GetDataSize(int64_t *size) override; + NS_IMETHOD GetAltDataSize(int64_t *size) override; NS_IMETHOD OpenInputStream(int64_t offset, nsIInputStream * *_retval) override; NS_IMETHOD OpenOutputStream(int64_t offset, nsIOutputStream * *_retval) override; NS_IMETHOD MaybeMarkValid() override; diff --git a/netwerk/cache2/nsICacheEntry.idl b/netwerk/cache2/nsICacheEntry.idl index a8c093b46e3f..784523a01541 100644 --- a/netwerk/cache2/nsICacheEntry.idl +++ b/netwerk/cache2/nsICacheEntry.idl @@ -196,6 +196,15 @@ interface nsICacheEntry : nsISupports */ readonly attribute long long dataSize; + /** + * Returns the length of data this entry holds. + * @throws + * - NS_ERROR_IN_PROGRESS when a write is still in progress (either real + content or alt data). + * - NS_ERROR_NOT_AVAILABLE if alt data does not exist. + */ + readonly attribute long long altDataSize; + /** * Opens and returns an output stream that a consumer may use to save an * alternate representation of the data. diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index 5dbe0b6dff5f..a5b5bc327254 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -4505,9 +4505,13 @@ nsHttpChannel::OpenCacheInputStream(nsICacheEntry* cacheEntry, bool startBufferi if (NS_SUCCEEDED(rv)) { // We have succeeded. mAvailableCachedAltDataType = mPreferredCachedAltDataType; - // The alternative data may have a different length than the original - // content, so we clear the Content-Length header + // Clear the header. mCachedResponseHead->SetContentLength(-1); + // Set the correct data size on the channel. + int64_t altDataSize; + if (NS_SUCCEEDED(cacheEntry->GetAltDataSize(&altDataSize))) { + mCachedResponseHead->SetContentLength(altDataSize); + } } } diff --git a/netwerk/test/unit/test_alt-data_simple.js b/netwerk/test/unit/test_alt-data_simple.js index 6066eddf0835..a140809231da 100644 --- a/netwerk/test/unit/test_alt-data_simple.js +++ b/netwerk/test/unit/test_alt-data_simple.js @@ -61,7 +61,7 @@ function run_test() var cc = chan.QueryInterface(Ci.nsICacheInfoChannel); cc.preferAlternativeDataType(altContentType); - chan.asyncOpen2(new ChannelListener(readServerContent, null, CL_ALLOW_UNKNOWN_CL)); + chan.asyncOpen2(new ChannelListener(readServerContent, null)); do_test_pending(); } From 632626f6395692fd359d3687a5885a777f7d841e Mon Sep 17 00:00:00 2001 From: Valentin Gosu Date: Tue, 27 Sep 2016 10:26:32 +0200 Subject: [PATCH 016/102] Bug 1231565 - (Part 4) Test that large alt-data content can be saved, and that streaming works r=honzab --HG-- rename : netwerk/test/unit/test_alt-data_simple.js => netwerk/test/unit/test_alt-data_stream.js rename : netwerk/test/unit_ipc/test_alt-data_simple_wrap.js => netwerk/test/unit_ipc/test_alt-data_stream_wrap.js --- netwerk/test/unit/test_alt-data_stream.js | 120 ++++++++++++++++++ netwerk/test/unit/xpcshell.ini | 1 + .../unit_ipc/test_alt-data_stream_wrap.js | 3 + netwerk/test/unit_ipc/xpcshell.ini | 2 + 4 files changed, 126 insertions(+) create mode 100644 netwerk/test/unit/test_alt-data_stream.js create mode 100644 netwerk/test/unit_ipc/test_alt-data_stream_wrap.js diff --git a/netwerk/test/unit/test_alt-data_stream.js b/netwerk/test/unit/test_alt-data_stream.js new file mode 100644 index 000000000000..da3794dd0654 --- /dev/null +++ b/netwerk/test/unit/test_alt-data_stream.js @@ -0,0 +1,120 @@ +/** + * Test for the "alternative data stream" stored withing a cache entry. + * + * - we load a URL with preference for an alt data (check what we get is the raw data, + * since there was nothing previously cached) + * - we write a big chunk of alt-data to the output stream + * - we load the URL again, expecting to get alt-data + * - we check that the alt-data is streamed. We should get the first chunk, then + * the rest of the alt-data is written, and we check that it is received in + * the proper order. + * + */ + +Cu.import("resource://testing-common/httpd.js"); +Cu.import("resource://gre/modules/NetUtil.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +XPCOMUtils.defineLazyGetter(this, "URL", function() { + return "http://localhost:" + httpServer.identity.primaryPort + "/content"; +}); + +var httpServer = null; + +function make_channel(url, callback, ctx) { + return NetUtil.newChannel({uri: url, loadUsingSystemPrincipal: true}); +} + +const responseContent = "response body"; +// We need a large content in order to make sure that the IPDL stream is cut +// into several different chunks. +// We fill each chunk with a different character for easy debugging. +const altContent = "a".repeat(128*1024) + + "b".repeat(128*1024) + + "c".repeat(128*1024) + + "d".repeat(128*1024) + + "e".repeat(128*1024) + + "f".repeat(128*1024) + + "g".repeat(128*1024) + + "h".repeat(128*1024) + + "i".repeat(13); // Just so the chunk size doesn't match exactly. + +const firstChunkSize = Math.floor(altContent.length / 4); +const altContentType = "text/binary"; + +function contentHandler(metadata, response) +{ + response.setHeader("Content-Type", "text/plain"); + response.setHeader("Cache-Control", "max-age=86400"); + + response.bodyOutputStream.write(responseContent, responseContent.length); +} + +function run_test() +{ + do_get_profile(); + httpServer = new HttpServer(); + httpServer.registerPathHandler("/content", contentHandler); + httpServer.start(-1); + + var chan = make_channel(URL); + + var cc = chan.QueryInterface(Ci.nsICacheInfoChannel); + cc.preferAlternativeDataType(altContentType); + + chan.asyncOpen2(new ChannelListener(readServerContent, null)); + do_test_pending(); +} + +// Output stream used to write alt-data to the cache entry. +var os; + +function readServerContent(request, buffer) +{ + var cc = request.QueryInterface(Ci.nsICacheInfoChannel); + + do_check_eq(buffer, responseContent); + do_check_eq(cc.alternativeDataType, ""); + + do_execute_soon(() => { + os = cc.openAlternativeOutputStream(altContentType); + // Write a quarter of the alt data content + os.write(altContent, firstChunkSize); + + do_execute_soon(openAltChannel); + }); +} + +function openAltChannel() +{ + var chan = make_channel(URL); + var cc = chan.QueryInterface(Ci.nsICacheInfoChannel); + cc.preferAlternativeDataType(altContentType); + + chan.asyncOpen2(listener); +} + +var listener = { + buffer: "", + onStartRequest: function(request, context) { }, + onDataAvailable: function(request, context, stream, offset, count) { + let string = NetUtil.readInputStreamToString(stream, count); + this.buffer += string; + + // XXX: this condition might be a bit volatile. If this test times out, + // it probably means that for some reason, the listener didn't get all the + // data in the first chunk. + if (this.buffer.length == firstChunkSize) { + // write the rest of the content + os.write(altContent.substring(firstChunkSize, altContent.length), altContent.length - firstChunkSize); + os.close(); + } + }, + onStopRequest: function(request, context, status) { + var cc = request.QueryInterface(Ci.nsICacheInfoChannel); + do_check_eq(cc.alternativeDataType, altContentType); + do_check_eq(this.buffer.length, altContent.length); + do_check_eq(this.buffer, altContent); + httpServer.stop(do_test_finished); + }, +}; diff --git a/netwerk/test/unit/xpcshell.ini b/netwerk/test/unit/xpcshell.ini index 73a4ce4b1730..1bdda2fab8ac 100644 --- a/netwerk/test/unit/xpcshell.ini +++ b/netwerk/test/unit/xpcshell.ini @@ -359,6 +359,7 @@ skip-if = os == "android" [test_bug412457.js] [test_bug464591.js] [test_alt-data_simple.js] +[test_alt-data_stream.js] [test_cache-control_request.js] [test_bug1279246.js] [test_throttlequeue.js] diff --git a/netwerk/test/unit_ipc/test_alt-data_stream_wrap.js b/netwerk/test/unit_ipc/test_alt-data_stream_wrap.js new file mode 100644 index 000000000000..1eee2f2434fe --- /dev/null +++ b/netwerk/test/unit_ipc/test_alt-data_stream_wrap.js @@ -0,0 +1,3 @@ +function run_test() { + run_test_in_child("../unit/test_alt-data_stream.js"); +} diff --git a/netwerk/test/unit_ipc/xpcshell.ini b/netwerk/test/unit_ipc/xpcshell.ini index ea7d7c22ae56..f9818947ffe8 100644 --- a/netwerk/test/unit_ipc/xpcshell.ini +++ b/netwerk/test/unit_ipc/xpcshell.ini @@ -55,6 +55,7 @@ support-files = child_app_offline.js !/netwerk/test/unit/data/test_readline8.txt !/netwerk/test/unit/data/signed_win.exe !/netwerk/test/unit/test_alt-data_simple.js + !/netwerk/test/unit/test_alt-data_stream.js [test_bug528292_wrap.js] [test_bug248970_cookie_wrap.js] @@ -95,6 +96,7 @@ skip-if = true [test_app_offline_http.js] [test_getHost_wrap.js] [test_alt-data_simple_wrap.js] +[test_alt-data_stream_wrap.js] [test_app_offline_notifications.js] [test_original_sent_received_head_wrap.js] [test_channel_id.js] From 17db78f2b59419e66b4b7531e0db3de68d8e11fe Mon Sep 17 00:00:00 2001 From: Gijs Kruitbosch Date: Tue, 6 Sep 2016 14:19:45 +0100 Subject: [PATCH 017/102] Bug 1284395, r=bz,mconley,baku MozReview-Commit-ID: 1nPyv7G3q7d --HG-- extra : rebase_source : 9b0b75c43d441a13992f085ce6f766aee0614666 extra : source : 6036b8acdab58eb565f15e12f8184f8abe7c6413 --- browser/base/content/browser.js | 26 +++++++++----- browser/base/content/content.js | 1 + browser/base/content/nsContextMenu.js | 1 + browser/base/content/tabbrowser.xml | 9 +++++ browser/base/content/test/general/browser.ini | 1 + ...browser_modifiedclick_inherit_principal.js | 30 ++++++++++++++++ browser/base/content/utilityOverlay.js | 11 +++++- browser/modules/ContentClick.jsm | 15 ++++---- toolkit/content/browser-child.js | 13 +++++++ toolkit/content/widgets/browser.xml | 10 ++++++ toolkit/content/widgets/remote-browser.xml | 9 +++++ toolkit/modules/BrowserUtils.jsm | 36 +++++++++++++++++++ 12 files changed, 147 insertions(+), 15 deletions(-) create mode 100644 browser/base/content/test/general/browser_modifiedclick_inherit_principal.js diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index efcc08720e02..51d3bb382358 100755 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -1128,6 +1128,7 @@ var gBrowserInit = { // [4]: allowThirdPartyFixup (bool) // [5]: referrerPolicy (int) // [6]: userContextId (int) + // [7]: originPrincipal (nsIPrincipal) else if (window.arguments.length >= 3) { let referrerURI = window.arguments[2]; if (typeof(referrerURI) == "string") { @@ -1142,7 +1143,10 @@ var gBrowserInit = { let userContextId = (window.arguments[6] != undefined ? window.arguments[6] : Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID); loadURI(uriToLoad, referrerURI, window.arguments[3] || null, - window.arguments[4] || false, referrerPolicy, userContextId); + window.arguments[4] || false, referrerPolicy, userContextId, + // pass the origin principal (if any) and force its use to create + // an initial about:blank viewer if present: + window.arguments[7], !!window.arguments[7]); window.focus(); } // Note: loadOneOrMoreURIs *must not* be called if window.arguments.length >= 3. @@ -2033,14 +2037,17 @@ function BrowserTryToCloseWindow() } function loadURI(uri, referrer, postData, allowThirdPartyFixup, referrerPolicy, - userContextId) { + userContextId, originPrincipal, forceAboutBlankViewerInCurrent) { try { openLinkIn(uri, "current", { referrerURI: referrer, referrerPolicy: referrerPolicy, postData: postData, allowThirdPartyFixup: allowThirdPartyFixup, - userContextId: userContextId }); + userContextId: userContextId, + originPrincipal, + forceAboutBlankViewerInCurrent, + }); } catch (e) {} } @@ -5584,11 +5591,14 @@ function handleLinkClick(event, href, linkNode) { } urlSecurityCheck(href, doc.nodePrincipal); - let params = { charset: doc.characterSet, - allowMixedContent: persistAllowMixedContentInChildTab, - referrerURI: referrerURI, - referrerPolicy: referrerPolicy, - noReferrer: BrowserUtils.linkHasNoReferrer(linkNode) }; + let params = { + charset: doc.characterSet, + allowMixedContent: persistAllowMixedContentInChildTab, + referrerURI: referrerURI, + referrerPolicy: referrerPolicy, + noReferrer: BrowserUtils.linkHasNoReferrer(linkNode), + originPrincipal: doc.nodePrincipal, + }; // The new tab/window must use the same userContextId if (doc.nodePrincipal.originAttributes.userContextId) { diff --git a/browser/base/content/content.js b/browser/base/content/content.js index 5cd36097de9e..0c43e1554b68 100644 --- a/browser/base/content/content.js +++ b/browser/base/content/content.js @@ -507,6 +507,7 @@ var ClickEventHandler = { json.allowMixedContent = true; } catch (e) {} } + json.originPrincipal = ownerDoc.nodePrincipal; sendAsyncMessage("Content:Click", json); return; diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js index 2aca5ed14908..4f0ad432d846 100644 --- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -965,6 +965,7 @@ nsContextMenu.prototype = { _openLinkInParameters : function (extra) { let params = { charset: gContextMenuContentData.charSet, + originPrincipal: this.principal, referrerURI: gContextMenuContentData.documentURIObject, referrerPolicy: gContextMenuContentData.referrerPolicy, noReferrer: this.linkHasNoReferrer }; diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index e5db1fa93203..e29eb7231ac4 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -1500,6 +1500,7 @@ var aNoReferrer; var aUserContextId; var aRelatedBrowser; + var aOriginPrincipal; if (arguments.length == 2 && typeof arguments[1] == "object" && !(arguments[1] instanceof Ci.nsIURI)) { @@ -1518,6 +1519,7 @@ aNoReferrer = params.noReferrer; aUserContextId = params.userContextId; aRelatedBrowser = params.relatedBrowser; + aOriginPrincipal = params.originPrincipal; } var bgLoad = (aLoadInBackground != null) ? aLoadInBackground : @@ -1537,6 +1539,7 @@ forceNotRemote: aForceNotRemote, noReferrer: aNoReferrer, userContextId: aUserContextId, + originPrincipal: aOriginPrincipal, relatedBrowser: aRelatedBrowser }); if (!bgLoad) this.selectedTab = tab; @@ -2043,6 +2046,7 @@ var aUserContextId; var aEventDetail; var aRelatedBrowser; + var aOriginPrincipal; if (arguments.length == 2 && typeof arguments[1] == "object" && !(arguments[1] instanceof Ci.nsIURI)) { @@ -2062,6 +2066,7 @@ aUserContextId = params.userContextId; aEventDetail = params.eventDetail; aRelatedBrowser = params.relatedBrowser; + aOriginPrincipal = params.originPrincipal; } // if we're adding tabs, we're past interrupt mode, ditch the owner @@ -2141,6 +2146,10 @@ var evt = new CustomEvent("TabOpen", { bubbles: true, detail }); t.dispatchEvent(evt); + if (!usingPreloadedContent && aOriginPrincipal) { + b.createAboutBlankContentViewer(aOriginPrincipal); + } + // If we didn't swap docShells with a preloaded browser // then let's just continue loading the page normally. if (!usingPreloadedContent && !uriIsAboutBlank) { diff --git a/browser/base/content/test/general/browser.ini b/browser/base/content/test/general/browser.ini index 7e40f041587b..f8b7b1b30eb2 100644 --- a/browser/base/content/test/general/browser.ini +++ b/browser/base/content/test/general/browser.ini @@ -342,6 +342,7 @@ subsuite = clipboard [browser_mixed_content_cert_override.js] [browser_mixedcontent_securityflags.js] tags = mcb +[browser_modifiedclick_inherit_principal.js] [browser_offlineQuotaNotification.js] skip-if = buildapp == 'mulet' [browser_feed_discovery.js] diff --git a/browser/base/content/test/general/browser_modifiedclick_inherit_principal.js b/browser/base/content/test/general/browser_modifiedclick_inherit_principal.js new file mode 100644 index 000000000000..3b5a5a149492 --- /dev/null +++ b/browser/base/content/test/general/browser_modifiedclick_inherit_principal.js @@ -0,0 +1,30 @@ +"use strict"; + +const kURL = + "http://example.com/browser/browser/base/content/test/general/dummy_page.html"; + "data:text/html,Middle-click me"; + +/* + * Check that when manually opening content JS links in new tabs/windows, + * we use the correct principal, and we don't clear the URL bar. + */ +add_task(function* () { + yield BrowserTestUtils.withNewTab(kURL, function* (browser) { + let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser); + yield ContentTask.spawn(browser, null, function* () { + let a = content.document.createElement("a"); + a.href = "javascript:document.write('spoof'); void(0);"; + a.textContent = "Some link"; + content.document.body.appendChild(a); + }); + info("Added element"); + yield BrowserTestUtils.synthesizeMouseAtCenter("a", {button: 1}, browser); + let newTab = yield newTabPromise; + is(newTab.linkedBrowser.contentPrincipal.origin, "http://example.com", + "Principal should be for example.com"); + yield BrowserTestUtils.switchTab(gBrowser, newTab); + info(gURLBar.value); + isnot(gURLBar.value, "", "URL bar should not be empty."); + yield BrowserTestUtils.removeTab(newTab); + }); +}); diff --git a/browser/base/content/utilityOverlay.js b/browser/base/content/utilityOverlay.js index 24de93c9a919..bfc73e9868ff 100644 --- a/browser/base/content/utilityOverlay.js +++ b/browser/base/content/utilityOverlay.js @@ -222,6 +222,9 @@ function openLinkIn(url, where, params) { var aAllowPopups = !!params.allowPopups; var aUserContextId = params.userContextId; var aIndicateErrorPageLoad = params.indicateErrorPageLoad; + var aPrincipal = params.originPrincipal; + var aForceAboutBlankViewerInCurrent = + params.forceAboutBlankViewerInCurrent; if (where == "save") { // TODO(1073187): propagate referrerPolicy. @@ -290,6 +293,7 @@ function openLinkIn(url, where, params) { sa.AppendElement(allowThirdPartyFixupSupports); sa.AppendElement(referrerPolicySupports); sa.AppendElement(userContextIdSupports); + sa.AppendElement(aPrincipal); let features = "chrome,dialog=no,all"; if (aIsPrivate) { @@ -357,6 +361,10 @@ function openLinkIn(url, where, params) { flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ERROR_LOAD_CHANGES_RV; } + if (aForceAboutBlankViewerInCurrent) { + w.gBrowser.selectedBrowser.createAboutBlankContentViewer(aPrincipal); + } + w.gBrowser.loadURIWithFlags(url, { flags: flags, referrerURI: aNoReferrer ? null : aReferrerURI, @@ -380,7 +388,8 @@ function openLinkIn(url, where, params) { skipAnimation: aSkipTabAnimation, allowMixedContent: aAllowMixedContent, noReferrer: aNoReferrer, - userContextId: aUserContextId + userContextId: aUserContextId, + originPrincipal: aPrincipal, }); break; } diff --git a/browser/modules/ContentClick.jsm b/browser/modules/ContentClick.jsm index 679bcca71b79..8abc32525c63 100644 --- a/browser/modules/ContentClick.jsm +++ b/browser/modules/ContentClick.jsm @@ -77,12 +77,15 @@ var ContentClick = { // Todo(903022): code for where == save - let params = { charset: browser.characterSet, - referrerURI: browser.documentURI, - referrerPolicy: json.referrerPolicy, - noReferrer: json.noReferrer, - allowMixedContent: json.allowMixedContent, - isContentWindowPrivate: json.isContentWindowPrivate}; + let params = { + charset: browser.characterSet, + referrerURI: browser.documentURI, + referrerPolicy: json.referrerPolicy, + noReferrer: json.noReferrer, + allowMixedContent: json.allowMixedContent, + isContentWindowPrivate: json.isContentWindowPrivate, + originPrincipal: json.originPrincipal, + }; // The new tab/window must use the same userContextId. if (json.originAttributes.userContextId) { diff --git a/toolkit/content/browser-child.js b/toolkit/content/browser-child.js index 9d7c1e67eb19..c819e3db65f2 100644 --- a/toolkit/content/browser-child.js +++ b/toolkit/content/browser-child.js @@ -8,6 +8,7 @@ var Cu = Components.utils; var Cr = Components.results; Cu.import("resource://gre/modules/AppConstants.jsm"); +Cu.import("resource://gre/modules/BrowserUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import('resource://gre/modules/XPCOMUtils.jsm'); Cu.import("resource://gre/modules/RemoteAddonsChild.jsm"); @@ -565,6 +566,18 @@ addMessageListener("Browser:Thumbnail:GetOriginalURL", function (aMessage) { }); }); +/** + * Remote createAboutBlankContentViewer request handler. + */ +addMessageListener("Browser:CreateAboutBlank", function(aMessage) { + if (!content.document || content.document.documentURI != "about:blank") { + throw new Error("Can't create a content viewer unless on about:blank"); + } + let principal = aMessage.data; + principal = BrowserUtils.principalWithMatchingOA(principal, content.document.nodePrincipal); + docShell.createAboutBlankContentViewer(principal); +}); + // The AddonsChild needs to be rooted so that it stays alive as long as // the tab. var AddonsChild = RemoteAddonsChild.init(this); diff --git a/toolkit/content/widgets/browser.xml b/toolkit/content/widgets/browser.xml index 99f490ad6248..52bd7b758491 100644 --- a/toolkit/content/widgets/browser.xml +++ b/toolkit/content/widgets/browser.xml @@ -1038,6 +1038,16 @@ + + + + + + + 10 false null diff --git a/toolkit/content/widgets/remote-browser.xml b/toolkit/content/widgets/remote-browser.xml index dd7f74092ab2..5f2059295dcc 100644 --- a/toolkit/content/widgets/remote-browser.xml +++ b/toolkit/content/widgets/remote-browser.xml @@ -561,6 +561,15 @@ ]]> + + + + + + + diff --git a/toolkit/modules/BrowserUtils.jsm b/toolkit/modules/BrowserUtils.jsm index 993dfe5096a7..e883c508e5ea 100644 --- a/toolkit/modules/BrowserUtils.jsm +++ b/toolkit/modules/BrowserUtils.jsm @@ -82,6 +82,42 @@ this.BrowserUtils = { } }, + /** + * Return or create a principal with the codebase of one, and the originAttributes + * of an existing principal (e.g. on a docshell, where the originAttributes ought + * not to change, that is, we should keep the userContextId, privateBrowsingId, + * etc. the same when changing the principal). + * + * @param principal + * The principal whose codebase/null/system-ness we want. + * @param existingPrincipal + * The principal whose originAttributes we want, usually the current + * principal of a docshell. + * @return an nsIPrincipal that matches the codebase/null/system-ness of the first + * param, and the originAttributes of the second. + */ + principalWithMatchingOA(principal, existingPrincipal) { + // Don't care about system principals: + if (principal.isSystemPrincipal) { + return principal; + } + + // If the originAttributes already match, just return the principal as-is. + if (existingPrincipal.originSuffix == principal.originSuffix) { + return principal; + } + + let secMan = Services.scriptSecurityManager; + if (principal.isCodebasePrincipal) { + return secMan.createCodebasePrincipal(principal.URI, existingPrincipal.originAttributes); + } + + if (principal.isNullPrincipal) { + return secMan.createNullPrincipal(existingPrincipal.originAttributes); + } + throw new Error("Can't change the originAttributes of an expanded principal!"); + }, + /** * Constructs a new URI, using nsIIOService. * @param aURL The URI spec. From 2cdba405f7aa53bcd08e17aa3e5888b8cdba19ec Mon Sep 17 00:00:00 2001 From: Philip Chee Date: Tue, 27 Sep 2016 16:48:14 +0800 Subject: [PATCH 018/102] Bug 1281005 - Move the nsPlacesAutocomplete component to Suite (mozilla-central part) r=mak77 --- toolkit/components/places/moz.build | 6 - .../components/places/nsPlacesAutoComplete.js | 1369 ----------------- .../places/nsPlacesAutoComplete.manifest | 3 - .../places/tests/autocomplete/.eslintrc | 5 - .../tests/autocomplete/head_autocomplete.js | 314 ---- .../places/tests/autocomplete/test_416211.js | 30 - .../places/tests/autocomplete/test_416214.js | 38 - .../places/tests/autocomplete/test_417798.js | 36 - .../places/tests/autocomplete/test_418257.js | 43 - .../places/tests/autocomplete/test_422277.js | 25 - ...st_autocomplete_on_value_removed_479089.js | 54 - .../test_download_embed_bookmarks.js | 53 - .../tests/autocomplete/test_empty_search.js | 69 - .../places/tests/autocomplete/test_enabled.js | 69 - .../tests/autocomplete/test_escape_self.js | 30 - .../autocomplete/test_ignore_protocol.js | 27 - .../tests/autocomplete/test_keyword_search.js | 73 - .../autocomplete/test_match_beginning.js | 45 - .../autocomplete/test_multi_word_search.js | 49 - .../tests/autocomplete/test_special_search.js | 183 --- .../tests/autocomplete/test_swap_protocol.js | 63 - .../tests/autocomplete/test_tabmatches.js | 97 -- .../autocomplete/test_word_boundary_search.js | 105 -- .../places/tests/autocomplete/xpcshell.ini | 29 - toolkit/components/places/tests/moz.build | 5 - 25 files changed, 2820 deletions(-) delete mode 100644 toolkit/components/places/nsPlacesAutoComplete.js delete mode 100644 toolkit/components/places/nsPlacesAutoComplete.manifest delete mode 100644 toolkit/components/places/tests/autocomplete/.eslintrc delete mode 100644 toolkit/components/places/tests/autocomplete/head_autocomplete.js delete mode 100644 toolkit/components/places/tests/autocomplete/test_416211.js delete mode 100644 toolkit/components/places/tests/autocomplete/test_416214.js delete mode 100644 toolkit/components/places/tests/autocomplete/test_417798.js delete mode 100644 toolkit/components/places/tests/autocomplete/test_418257.js delete mode 100644 toolkit/components/places/tests/autocomplete/test_422277.js delete mode 100644 toolkit/components/places/tests/autocomplete/test_autocomplete_on_value_removed_479089.js delete mode 100644 toolkit/components/places/tests/autocomplete/test_download_embed_bookmarks.js delete mode 100644 toolkit/components/places/tests/autocomplete/test_empty_search.js delete mode 100644 toolkit/components/places/tests/autocomplete/test_enabled.js delete mode 100644 toolkit/components/places/tests/autocomplete/test_escape_self.js delete mode 100644 toolkit/components/places/tests/autocomplete/test_ignore_protocol.js delete mode 100644 toolkit/components/places/tests/autocomplete/test_keyword_search.js delete mode 100644 toolkit/components/places/tests/autocomplete/test_match_beginning.js delete mode 100644 toolkit/components/places/tests/autocomplete/test_multi_word_search.js delete mode 100644 toolkit/components/places/tests/autocomplete/test_special_search.js delete mode 100644 toolkit/components/places/tests/autocomplete/test_swap_protocol.js delete mode 100644 toolkit/components/places/tests/autocomplete/test_tabmatches.js delete mode 100644 toolkit/components/places/tests/autocomplete/test_word_boundary_search.js delete mode 100644 toolkit/components/places/tests/autocomplete/xpcshell.ini diff --git a/toolkit/components/places/moz.build b/toolkit/components/places/moz.build index a3788dcf63e2..55ab218ef885 100644 --- a/toolkit/components/places/moz.build +++ b/toolkit/components/places/moz.build @@ -85,12 +85,6 @@ if CONFIG['MOZ_PLACES']: 'UnifiedComplete.js', ] - if CONFIG['MOZ_SUITE']: - EXTRA_COMPONENTS += [ - 'nsPlacesAutoComplete.js', - 'nsPlacesAutoComplete.manifest', - ] - FINAL_LIBRARY = 'xul' include('/ipc/chromium/chromium-config.mozbuild') diff --git a/toolkit/components/places/nsPlacesAutoComplete.js b/toolkit/components/places/nsPlacesAutoComplete.js deleted file mode 100644 index 30615fe072cc..000000000000 --- a/toolkit/components/places/nsPlacesAutoComplete.js +++ /dev/null @@ -1,1369 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- - * vim: sw=2 ts=2 sts=2 expandtab - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); -Components.utils.import("resource://gre/modules/Services.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", - "resource://gre/modules/PlacesUtils.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch", - "resource://gre/modules/TelemetryStopwatch.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", - "resource://gre/modules/NetUtil.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Task", - "resource://gre/modules/Task.jsm"); - -//////////////////////////////////////////////////////////////////////////////// -//// Constants - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cr = Components.results; - -// This SQL query fragment provides the following: -// - whether the entry is bookmarked (kQueryIndexBookmarked) -// - the bookmark title, if it is a bookmark (kQueryIndexBookmarkTitle) -// - the tags associated with a bookmarked entry (kQueryIndexTags) -const kBookTagSQLFragment = - `EXISTS(SELECT 1 FROM moz_bookmarks WHERE fk = h.id) AS bookmarked, - ( - SELECT title FROM moz_bookmarks WHERE fk = h.id AND title NOTNULL - ORDER BY lastModified DESC LIMIT 1 - ) AS btitle, - ( - SELECT GROUP_CONCAT(t.title, ',') - FROM moz_bookmarks b - JOIN moz_bookmarks t ON t.id = +b.parent AND t.parent = :parent - WHERE b.fk = h.id - ) AS tags`; - -// observer topics -const kTopicShutdown = "places-shutdown"; -const kPrefChanged = "nsPref:changed"; - -// Match type constants. These indicate what type of search function we should -// be using. -const MATCH_ANYWHERE = Ci.mozIPlacesAutoComplete.MATCH_ANYWHERE; -const MATCH_BOUNDARY_ANYWHERE = Ci.mozIPlacesAutoComplete.MATCH_BOUNDARY_ANYWHERE; -const MATCH_BOUNDARY = Ci.mozIPlacesAutoComplete.MATCH_BOUNDARY; -const MATCH_BEGINNING = Ci.mozIPlacesAutoComplete.MATCH_BEGINNING; -const MATCH_BEGINNING_CASE_SENSITIVE = Ci.mozIPlacesAutoComplete.MATCH_BEGINNING_CASE_SENSITIVE; - -// AutoComplete index constants. All AutoComplete queries will provide these -// columns in this order. -const kQueryIndexURL = 0; -const kQueryIndexTitle = 1; -const kQueryIndexFaviconURL = 2; -const kQueryIndexBookmarked = 3; -const kQueryIndexBookmarkTitle = 4; -const kQueryIndexTags = 5; -const kQueryIndexVisitCount = 6; -const kQueryIndexTyped = 7; -const kQueryIndexPlaceId = 8; -const kQueryIndexQueryType = 9; -const kQueryIndexOpenPageCount = 10; - -// AutoComplete query type constants. Describes the various types of queries -// that we can process. -const kQueryTypeKeyword = 0; -const kQueryTypeFiltered = 1; - -// This separator is used as an RTL-friendly way to split the title and tags. -// It can also be used by an nsIAutoCompleteResult consumer to re-split the -// "comment" back into the title and the tag. -const kTitleTagsSeparator = " \u2013 "; - -const kBrowserUrlbarBranch = "browser.urlbar."; -// Toggle autocomplete. -const kBrowserUrlbarAutocompleteEnabledPref = "autocomplete.enabled"; - -//////////////////////////////////////////////////////////////////////////////// -//// Globals - -XPCOMUtils.defineLazyServiceGetter(this, "gTextURIService", - "@mozilla.org/intl/texttosuburi;1", - "nsITextToSubURI"); - -//////////////////////////////////////////////////////////////////////////////// -//// Helpers - -/** - * Initializes our temporary table on a given database. - * - * @param aDatabase - * The mozIStorageConnection to set up the temp table on. - */ -function initTempTable(aDatabase) -{ - // Note: this should be kept up-to-date with the definition in - // nsPlacesTables.h. - let stmt = aDatabase.createAsyncStatement( - `CREATE TEMP TABLE moz_openpages_temp ( - url TEXT PRIMARY KEY - , open_count INTEGER - )` - ); - stmt.executeAsync(); - stmt.finalize(); - - // Note: this should be kept up-to-date with the definition in - // nsPlacesTriggers.h. - stmt = aDatabase.createAsyncStatement( - `CREATE TEMPORARY TRIGGER moz_openpages_temp_afterupdate_trigger - AFTER UPDATE OF open_count ON moz_openpages_temp FOR EACH ROW - WHEN NEW.open_count = 0 - BEGIN - DELETE FROM moz_openpages_temp - WHERE url = NEW.url; - END` - ); - stmt.executeAsync(); - stmt.finalize(); -} - -/** - * Used to unescape encoded URI strings, and drop information that we do not - * care about for searching. - * - * @param aURIString - * The text to unescape and modify. - * @return the modified uri. - */ -function fixupSearchText(aURIString) -{ - let uri = stripPrefix(aURIString); - return gTextURIService.unEscapeURIForUI("UTF-8", uri); -} - -/** - * Strip prefixes from the URI that we don't care about for searching. - * - * @param aURIString - * The text to modify. - * @return the modified uri. - */ -function stripPrefix(aURIString) -{ - let uri = aURIString; - - if (uri.indexOf("http://") == 0) { - uri = uri.slice(7); - } - else if (uri.indexOf("https://") == 0) { - uri = uri.slice(8); - } - else if (uri.indexOf("ftp://") == 0) { - uri = uri.slice(6); - } - - if (uri.indexOf("www.") == 0) { - uri = uri.slice(4); - } - return uri; -} - -/** - * safePrefGetter get the pref with type safety. - * This will return the default value provided if no pref is set. - * - * @param aPrefBranch - * The nsIPrefBranch containing the required preference - * @param aName - * A preference name - * @param aDefault - * The preference's default value - * @return the preference value or provided default - */ - -function safePrefGetter(aPrefBranch, aName, aDefault) { - let types = { - boolean: "Bool", - number: "Int", - string: "Char" - }; - let type = types[typeof(aDefault)]; - if (!type) { - throw "Unknown type!"; - } - - // If the pref isn't set, we want to use the default. - if (aPrefBranch.getPrefType(aName) == Ci.nsIPrefBranch.PREF_INVALID) { - return aDefault; - } - try { - return aPrefBranch["get" + type + "Pref"](aName); - } - catch (e) { - return aDefault; - } -} - -/** - * Whether UnifiedComplete is alive. - */ -function isUnifiedCompleteInstantiated() { - try { - return Components.manager.QueryInterface(Ci.nsIServiceManager) - .isServiceInstantiated(Cc["@mozilla.org/autocomplete/search;1?name=unifiedcomplete"], - Ci.mozIPlacesAutoComplete); - } catch (ex) { - return false; - } -} - -//////////////////////////////////////////////////////////////////////////////// -//// AutoCompleteStatementCallbackWrapper class - -/** - * Wraps a callback and ensures that handleCompletion is not dispatched if the - * query is no longer tracked. - * - * @param aAutocomplete - * A reference to a nsPlacesAutoComplete. - * @param aCallback - * A reference to a mozIStorageStatementCallback - * @param aDBConnection - * The database connection to execute the queries on. - */ -function AutoCompleteStatementCallbackWrapper(aAutocomplete, aCallback, - aDBConnection) -{ - this._autocomplete = aAutocomplete; - this._callback = aCallback; - this._db = aDBConnection; -} - -AutoCompleteStatementCallbackWrapper.prototype = { - ////////////////////////////////////////////////////////////////////////////// - //// mozIStorageStatementCallback - - handleResult: function ACSCW_handleResult(aResultSet) - { - this._callback.handleResult.apply(this._callback, arguments); - }, - - handleError: function ACSCW_handleError(aError) - { - this._callback.handleError.apply(this._callback, arguments); - }, - - handleCompletion: function ACSCW_handleCompletion(aReason) - { - // Only dispatch handleCompletion if we are not done searching and are a - // pending search. - if (!this._autocomplete.isSearchComplete() && - this._autocomplete.isPendingSearch(this._handle)) { - this._callback.handleCompletion.apply(this._callback, arguments); - } - }, - - ////////////////////////////////////////////////////////////////////////////// - //// AutoCompleteStatementCallbackWrapper - - /** - * Executes the specified query asynchronously. This object will notify - * this._callback if we should notify (logic explained in handleCompletion). - * - * @param aQueries - * The queries to execute asynchronously. - * @return a mozIStoragePendingStatement that can be used to cancel the - * queries. - */ - executeAsync: function ACSCW_executeAsync(aQueries) - { - return this._handle = this._db.executeAsync(aQueries, aQueries.length, - this); - }, - - ////////////////////////////////////////////////////////////////////////////// - //// nsISupports - - QueryInterface: XPCOMUtils.generateQI([ - Ci.mozIStorageStatementCallback, - ]) -}; - -//////////////////////////////////////////////////////////////////////////////// -//// nsPlacesAutoComplete class -//// @mozilla.org/autocomplete/search;1?name=history - -function nsPlacesAutoComplete() -{ - ////////////////////////////////////////////////////////////////////////////// - //// Shared Constants for Smart Getters - - // TODO bug 412736 in case of a frecency tie, break it with h.typed and - // h.visit_count which is better than nothing. This is slow, so not doing it - // yet... - function baseQuery(conditions = "") { - let query = `SELECT h.url, h.title, f.url, ${kBookTagSQLFragment}, - h.visit_count, h.typed, h.id, :query_type, - t.open_count - FROM moz_places h - LEFT JOIN moz_favicons f ON f.id = h.favicon_id - LEFT JOIN moz_openpages_temp t ON t.url = h.url - WHERE h.frecency <> 0 - AND AUTOCOMPLETE_MATCH(:searchString, h.url, - IFNULL(btitle, h.title), tags, - h.visit_count, h.typed, - bookmarked, t.open_count, - :matchBehavior, :searchBehavior) - ${conditions} - ORDER BY h.frecency DESC, h.id DESC - LIMIT :maxResults`; - return query; - } - - ////////////////////////////////////////////////////////////////////////////// - //// Smart Getters - - XPCOMUtils.defineLazyGetter(this, "_db", function() { - // Get a cloned, read-only version of the database. We'll only ever write - // to our own in-memory temp table, and having a cloned copy means we do not - // run the risk of our queries taking longer due to the main database - // connection performing a long-running task. - let db = PlacesUtils.history.DBConnection.clone(true); - - // Autocomplete often fallbacks to a table scan due to lack of text indices. - // In such cases a larger cache helps reducing IO. The default Storage - // value is MAX_CACHE_SIZE_BYTES in storage/mozStorageConnection.cpp. - let stmt = db.createAsyncStatement("PRAGMA cache_size = -6144"); // 6MiB - stmt.executeAsync(); - stmt.finalize(); - - // Create our in-memory tables for tab tracking. - initTempTable(db); - - // Populate the table with current open pages cache contents. - if (this._openPagesCache.length > 0) { - // Avoid getter re-entrance from the _registerOpenPageQuery lazy getter. - let stmt = this._registerOpenPageQuery = - db.createAsyncStatement(this._registerOpenPageQuerySQL); - let params = stmt.newBindingParamsArray(); - for (let i = 0; i < this._openPagesCache.length; i++) { - let bp = params.newBindingParams(); - bp.bindByName("page_url", this._openPagesCache[i]); - params.addParams(bp); - } - stmt.bindParameters(params); - stmt.executeAsync(); - stmt.finalize(); - delete this._openPagesCache; - } - - return db; - }); - - this._customQuery = (conditions = "") => { - return this._db.createAsyncStatement(baseQuery(conditions)); - }; - - XPCOMUtils.defineLazyGetter(this, "_defaultQuery", function() { - return this._db.createAsyncStatement(baseQuery()); - }); - - XPCOMUtils.defineLazyGetter(this, "_historyQuery", function() { - // Enforce ignoring the visit_count index, since the frecency one is much - // faster in this case. ANALYZE helps the query planner to figure out the - // faster path, but it may not have run yet. - return this._db.createAsyncStatement(baseQuery("AND +h.visit_count > 0")); - }); - - XPCOMUtils.defineLazyGetter(this, "_bookmarkQuery", function() { - return this._db.createAsyncStatement(baseQuery("AND bookmarked")); - }); - - XPCOMUtils.defineLazyGetter(this, "_tagsQuery", function() { - return this._db.createAsyncStatement(baseQuery("AND tags IS NOT NULL")); - }); - - XPCOMUtils.defineLazyGetter(this, "_openPagesQuery", function() { - return this._db.createAsyncStatement( - `SELECT t.url, t.url, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - :query_type, t.open_count, NULL - FROM moz_openpages_temp t - LEFT JOIN moz_places h ON h.url_hash = hash(t.url) AND h.url = t.url - WHERE h.id IS NULL - AND AUTOCOMPLETE_MATCH(:searchString, t.url, t.url, NULL, - NULL, NULL, NULL, t.open_count, - :matchBehavior, :searchBehavior) - ORDER BY t.ROWID DESC - LIMIT :maxResults` - ); - }); - - XPCOMUtils.defineLazyGetter(this, "_typedQuery", function() { - return this._db.createAsyncStatement(baseQuery("AND h.typed = 1")); - }); - - XPCOMUtils.defineLazyGetter(this, "_adaptiveQuery", function() { - return this._db.createAsyncStatement( - `/* do not warn (bug 487789) */ - SELECT h.url, h.title, f.url, ${kBookTagSQLFragment}, - h.visit_count, h.typed, h.id, :query_type, t.open_count - FROM ( - SELECT ROUND( - MAX(use_count) * (1 + (input = :search_string)), 1 - ) AS rank, place_id - FROM moz_inputhistory - WHERE input BETWEEN :search_string AND :search_string || X'FFFF' - GROUP BY place_id - ) AS i - JOIN moz_places h ON h.id = i.place_id - LEFT JOIN moz_favicons f ON f.id = h.favicon_id - LEFT JOIN moz_openpages_temp t ON t.url = h.url - WHERE AUTOCOMPLETE_MATCH(NULL, h.url, - IFNULL(btitle, h.title), tags, - h.visit_count, h.typed, bookmarked, - t.open_count, - :matchBehavior, :searchBehavior) - ORDER BY rank DESC, h.frecency DESC` - ); - }); - - XPCOMUtils.defineLazyGetter(this, "_keywordQuery", function() { - return this._db.createAsyncStatement( - `/* do not warn (bug 487787) */ - SELECT REPLACE(h.url, '%s', :query_string) AS search_url, h.title, - IFNULL(f.url, (SELECT f.url - FROM moz_places - JOIN moz_favicons f ON f.id = favicon_id - WHERE rev_host = h.rev_host - ORDER BY frecency DESC - LIMIT 1) - ), 1, NULL, NULL, h.visit_count, h.typed, h.id, - :query_type, t.open_count - FROM moz_keywords k - JOIN moz_places h ON k.place_id = h.id - LEFT JOIN moz_favicons f ON f.id = h.favicon_id - LEFT JOIN moz_openpages_temp t ON t.url = search_url - WHERE k.keyword = LOWER(:keyword)` - ); - }); - - this._registerOpenPageQuerySQL = - `INSERT OR REPLACE INTO moz_openpages_temp (url, open_count) - VALUES (:page_url, - IFNULL( - ( - SELECT open_count + 1 - FROM moz_openpages_temp - WHERE url = :page_url - ), - 1 - ) - )`; - XPCOMUtils.defineLazyGetter(this, "_registerOpenPageQuery", function() { - return this._db.createAsyncStatement(this._registerOpenPageQuerySQL); - }); - - XPCOMUtils.defineLazyGetter(this, "_unregisterOpenPageQuery", function() { - return this._db.createAsyncStatement( - `UPDATE moz_openpages_temp - SET open_count = open_count - 1 - WHERE url = :page_url` - ); - }); - - ////////////////////////////////////////////////////////////////////////////// - //// Initialization - - // load preferences - this._prefs = Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefService). - getBranch(kBrowserUrlbarBranch); - this._syncEnabledPref(); - this._loadPrefs(true); - - // register observers - this._os = Cc["@mozilla.org/observer-service;1"]. - getService(Ci.nsIObserverService); - this._os.addObserver(this, kTopicShutdown, false); - -} - -nsPlacesAutoComplete.prototype = { - ////////////////////////////////////////////////////////////////////////////// - //// nsIAutoCompleteSearch - - startSearch: function PAC_startSearch(aSearchString, aSearchParam, - aPreviousResult, aListener) - { - // Stop the search in case the controller has not taken care of it. - this.stopSearch(); - - // Note: We don't use aPreviousResult to make sure ordering of results are - // consistent. See bug 412730 for more details. - - // We want to store the original string with no leading or trailing - // whitespace for case sensitive searches. - this._originalSearchString = aSearchString.trim(); - - this._currentSearchString = - fixupSearchText(this._originalSearchString.toLowerCase()); - - let params = new Set(aSearchParam.split(" ")); - this._enableActions = params.has("enable-actions"); - this._disablePrivateActions = params.has("disable-private-actions"); - - this._listener = aListener; - let result = Cc["@mozilla.org/autocomplete/simple-result;1"]. - createInstance(Ci.nsIAutoCompleteSimpleResult); - result.setSearchString(aSearchString); - result.setListener(this); - this._result = result; - - // If we are not enabled, we need to return now. - if (!this._enabled) { - this._finishSearch(true); - return; - } - - // Reset our search behavior to the default. - if (this._currentSearchString) { - this._behavior = this._defaultBehavior; - } - else { - this._behavior = this._emptySearchDefaultBehavior; - } - // For any given search, we run up to four queries: - // 1) keywords (this._keywordQuery) - // 2) adaptive learning (this._adaptiveQuery) - // 3) open pages not supported by history (this._openPagesQuery) - // 4) query from this._getSearch - // (1) only gets ran if we get any filtered tokens from this._getSearch, - // since if there are no tokens, there is nothing to match, so there is no - // reason to run the query). - let {query, tokens} = - this._getSearch(this._getUnfilteredSearchTokens(this._currentSearchString)); - let queries = tokens.length ? - [this._getBoundKeywordQuery(tokens), this._getBoundAdaptiveQuery()] : - [this._getBoundAdaptiveQuery()]; - - if (this._hasBehavior("openpage")) { - queries.push(this._getBoundOpenPagesQuery(tokens)); - } - queries.push(query); - - // Start executing our queries. - this._telemetryStartTime = Date.now(); - this._executeQueries(queries); - - // Set up our persistent state for the duration of the search. - this._searchTokens = tokens; - this._usedPlaces = {}; - }, - - stopSearch: function PAC_stopSearch() - { - // We need to cancel our searches so we do not get any [more] results. - // However, it's possible we haven't actually started any searches, so this - // method may throw because this._pendingQuery may be undefined. - if (this._pendingQuery) { - this._stopActiveQuery(); - } - - this._finishSearch(false); - }, - - ////////////////////////////////////////////////////////////////////////////// - //// nsIAutoCompleteSimpleResultListener - - onValueRemoved: function PAC_onValueRemoved(aResult, aURISpec, aRemoveFromDB) - { - if (aRemoveFromDB) { - PlacesUtils.history.removePage(NetUtil.newURI(aURISpec)); - } - }, - - ////////////////////////////////////////////////////////////////////////////// - //// mozIPlacesAutoComplete - - // If the connection has not yet been started, use this local cache. This - // prevents autocomplete from initing the database till the first search. - _openPagesCache: [], - registerOpenPage: function PAC_registerOpenPage(aURI) - { - if (!this._databaseInitialized) { - this._openPagesCache.push(aURI.spec); - return; - } - - let stmt = this._registerOpenPageQuery; - stmt.params.page_url = aURI.spec; - stmt.executeAsync(); - }, - - unregisterOpenPage: function PAC_unregisterOpenPage(aURI) - { - if (!this._databaseInitialized) { - let index = this._openPagesCache.indexOf(aURI.spec); - if (index != -1) { - this._openPagesCache.splice(index, 1); - } - return; - } - - let stmt = this._unregisterOpenPageQuery; - stmt.params.page_url = aURI.spec; - stmt.executeAsync(); - }, - - ////////////////////////////////////////////////////////////////////////////// - //// mozIStorageStatementCallback - - handleResult: function PAC_handleResult(aResultSet) - { - let row, haveMatches = false; - while ((row = aResultSet.getNextRow())) { - let match = this._processRow(row); - haveMatches = haveMatches || match; - - if (this._result.matchCount == this._maxRichResults) { - // We have enough results, so stop running our search. - this._stopActiveQuery(); - - // And finish our search. - this._finishSearch(true); - return; - } - - } - - // Notify about results if we've gotten them. - if (haveMatches) { - this._notifyResults(true); - } - }, - - handleError: function PAC_handleError(aError) - { - Components.utils.reportError("Places AutoComplete: An async statement encountered an " + - "error: " + aError.result + ", '" + aError.message + "'"); - }, - - handleCompletion: function PAC_handleCompletion(aReason) - { - // If we have already finished our search, we should bail out early. - if (this.isSearchComplete()) { - return; - } - - // If we do not have enough results, and our match type is - // MATCH_BOUNDARY_ANYWHERE, search again with MATCH_ANYWHERE to get more - // results. - if (this._matchBehavior == MATCH_BOUNDARY_ANYWHERE && - this._result.matchCount < this._maxRichResults && !this._secondPass) { - this._secondPass = true; - let queries = [ - this._getBoundAdaptiveQuery(MATCH_ANYWHERE), - this._getBoundSearchQuery(MATCH_ANYWHERE, this._searchTokens), - ]; - this._executeQueries(queries); - return; - } - - this._finishSearch(true); - }, - - ////////////////////////////////////////////////////////////////////////////// - //// nsIObserver - - observe: function PAC_observe(aSubject, aTopic, aData) - { - if (aTopic == kTopicShutdown) { - this._os.removeObserver(this, kTopicShutdown); - - // Remove our preference observer. - this._prefs.removeObserver("", this); - delete this._prefs; - - // Finalize the statements that we have used. - let stmts = [ - "_defaultQuery", - "_historyQuery", - "_bookmarkQuery", - "_tagsQuery", - "_openPagesQuery", - "_typedQuery", - "_adaptiveQuery", - "_keywordQuery", - "_registerOpenPageQuery", - "_unregisterOpenPageQuery", - ]; - for (let i = 0; i < stmts.length; i++) { - // We do not want to create any query we haven't already created, so - // see if it is a getter first. - if (Object.getOwnPropertyDescriptor(this, stmts[i]).value !== undefined) { - this[stmts[i]].finalize(); - } - } - - if (this._databaseInitialized) { - this._db.asyncClose(); - } - } - else if (aTopic == kPrefChanged) { - // Avoid re-entrancy when flipping linked preferences. - if (this._ignoreNotifications) - return; - this._ignoreNotifications = true; - this._loadPrefs(false, aTopic, aData); - this._ignoreNotifications = false; - } - }, - - ////////////////////////////////////////////////////////////////////////////// - //// nsPlacesAutoComplete - - get _databaseInitialized() { - return Object.getOwnPropertyDescriptor(this, "_db").value !== undefined; - }, - - /** - * Generates the tokens used in searching from a given string. - * - * @param aSearchString - * The string to generate tokens from. - * @return an array of tokens. - */ - _getUnfilteredSearchTokens: function PAC_unfilteredSearchTokens(aSearchString) - { - // Calling split on an empty string will return an array containing one - // empty string. We don't want that, as it'll break our logic, so return an - // empty array then. - return aSearchString.length ? aSearchString.split(" ") : []; - }, - - /** - * Properly cleans up when searching is completed. - * - * @param aNotify - * Indicates if we should notify the AutoComplete listener about our - * results or not. - */ - _finishSearch: function PAC_finishSearch(aNotify) - { - // Notify about results if we are supposed to. - if (aNotify) { - this._notifyResults(false); - } - - // Clear our state - delete this._originalSearchString; - delete this._currentSearchString; - delete this._strippedPrefix; - delete this._searchTokens; - delete this._listener; - delete this._result; - delete this._usedPlaces; - delete this._pendingQuery; - this._secondPass = false; - this._enableActions = false; - }, - - /** - * Executes the given queries asynchronously. - * - * @param aQueries - * The queries to execute. - */ - _executeQueries: function PAC_executeQueries(aQueries) - { - // Because we might get a handleCompletion for canceled queries, we want to - // filter out queries we no longer care about (described in the - // handleCompletion implementation of AutoCompleteStatementCallbackWrapper). - - // Create our wrapper object and execute the queries. - let wrapper = new AutoCompleteStatementCallbackWrapper(this, this, this._db); - this._pendingQuery = wrapper.executeAsync(aQueries); - }, - - /** - * Stops executing our active query. - */ - _stopActiveQuery: function PAC_stopActiveQuery() - { - this._pendingQuery.cancel(); - delete this._pendingQuery; - }, - - /** - * Notifies the listener about results. - * - * @param aSearchOngoing - * Indicates if the search is ongoing or not. - */ - _notifyResults: function PAC_notifyResults(aSearchOngoing) - { - let result = this._result; - let resultCode = result.matchCount ? "RESULT_SUCCESS" : "RESULT_NOMATCH"; - if (aSearchOngoing) { - resultCode += "_ONGOING"; - } - result.setSearchResult(Ci.nsIAutoCompleteResult[resultCode]); - this._listener.onSearchResult(this, result); - if (this._telemetryStartTime) { - let elapsed = Date.now() - this._telemetryStartTime; - if (elapsed > 50) { - try { - Services.telemetry - .getHistogramById("PLACES_AUTOCOMPLETE_1ST_RESULT_TIME_MS") - .add(elapsed); - } catch (ex) { - Components.utils.reportError("Unable to report telemetry."); - } - } - this._telemetryStartTime = null; - } - }, - - /** - * Synchronize suggest.* prefs with autocomplete.enabled. - */ - _syncEnabledPref: function PAC_syncEnabledPref() - { - let suggestPrefs = ["suggest.history", "suggest.bookmark", "suggest.openpage"]; - let types = ["History", "Bookmark", "Openpage"]; - - this._enabled = safePrefGetter(this._prefs, kBrowserUrlbarAutocompleteEnabledPref, - true); - this._suggestHistory = safePrefGetter(this._prefs, "suggest.history", true); - this._suggestBookmark = safePrefGetter(this._prefs, "suggest.bookmark", true); - this._suggestOpenpage = safePrefGetter(this._prefs, "suggest.openpage", true); - - if (this._enabled) { - // If the autocomplete preference is active, activate all suggest - // preferences only if all of them are false. - if (types.every(type => this["_suggest" + type] == false)) { - for (let type of suggestPrefs) { - this._prefs.setBoolPref(type, true); - } - } - } else { - // If the preference was deactivated, deactivate all suggest preferences. - for (let type of suggestPrefs) { - this._prefs.setBoolPref(type, false); - } - } - }, - - /** - * Loads the preferences that we care about. - * - * @param [optional] aRegisterObserver - * Indicates if the preference observer should be added or not. The - * default value is false. - * @param [optional] aTopic - * Observer's topic, if any. - * @param [optional] aSubject - * Observer's subject, if any. - */ - _loadPrefs: function PAC_loadPrefs(aRegisterObserver, aTopic, aData) - { - // Avoid race conditions with UnifiedComplete component. - if (aData && !isUnifiedCompleteInstantiated()) { - // Synchronize suggest.* prefs with autocomplete.enabled. - if (aData == kBrowserUrlbarAutocompleteEnabledPref) { - this._syncEnabledPref(); - } else if (aData.startsWith("suggest.")) { - let suggestPrefs = ["suggest.history", "suggest.bookmark", "suggest.openpage"]; - this._prefs.setBoolPref(kBrowserUrlbarAutocompleteEnabledPref, - suggestPrefs.some(pref => safePrefGetter(this._prefs, pref, true))); - } - } - - this._enabled = safePrefGetter(this._prefs, - kBrowserUrlbarAutocompleteEnabledPref, - true); - this._matchBehavior = safePrefGetter(this._prefs, - "matchBehavior", - MATCH_BOUNDARY_ANYWHERE); - this._filterJavaScript = safePrefGetter(this._prefs, "filter.javascript", true); - this._maxRichResults = safePrefGetter(this._prefs, "maxRichResults", 25); - this._restrictHistoryToken = safePrefGetter(this._prefs, - "restrict.history", "^"); - this._restrictBookmarkToken = safePrefGetter(this._prefs, - "restrict.bookmark", "*"); - this._restrictTypedToken = safePrefGetter(this._prefs, "restrict.typed", "~"); - this._restrictTagToken = safePrefGetter(this._prefs, "restrict.tag", "+"); - this._restrictOpenPageToken = safePrefGetter(this._prefs, - "restrict.openpage", "%"); - this._matchTitleToken = safePrefGetter(this._prefs, "match.title", "#"); - this._matchURLToken = safePrefGetter(this._prefs, "match.url", "@"); - - this._suggestHistory = safePrefGetter(this._prefs, "suggest.history", true); - this._suggestBookmark = safePrefGetter(this._prefs, "suggest.bookmark", true); - this._suggestOpenpage = safePrefGetter(this._prefs, "suggest.openpage", true); - this._suggestTyped = safePrefGetter(this._prefs, "suggest.history.onlyTyped", false); - - // If history is not set, onlyTyped value should be ignored. - if (!this._suggestHistory) { - this._suggestTyped = false; - } - let types = ["History", "Bookmark", "Openpage", "Typed"]; - this._defaultBehavior = types.reduce((memo, type) => { - let prefValue = this["_suggest" + type]; - return memo | (prefValue && - Ci.mozIPlacesAutoComplete["BEHAVIOR_" + type.toUpperCase()]); - }, 0); - - // Further restrictions to apply for "empty searches" (i.e. searches for ""). - // The empty behavior is typed history, if history is enabled. Otherwise, - // it is bookmarks, if they are enabled. If both history and bookmarks are disabled, - // it defaults to open pages. - this._emptySearchDefaultBehavior = Ci.mozIPlacesAutoComplete.BEHAVIOR_RESTRICT; - if (this._suggestHistory) { - this._emptySearchDefaultBehavior |= Ci.mozIPlacesAutoComplete.BEHAVIOR_HISTORY | - Ci.mozIPlacesAutoComplete.BEHAVIOR_TYPED; - } else if (this._suggestBookmark) { - this._emptySearchDefaultBehavior |= Ci.mozIPlacesAutoComplete.BEHAVIOR_BOOKMARK; - } else { - this._emptySearchDefaultBehavior |= Ci.mozIPlacesAutoComplete.BEHAVIOR_OPENPAGE; - } - - // Validate matchBehavior; default to MATCH_BOUNDARY_ANYWHERE. - if (this._matchBehavior != MATCH_ANYWHERE && - this._matchBehavior != MATCH_BOUNDARY && - this._matchBehavior != MATCH_BEGINNING) { - this._matchBehavior = MATCH_BOUNDARY_ANYWHERE; - } - // register observer - if (aRegisterObserver) { - this._prefs.addObserver("", this, false); - } - }, - - /** - * Given an array of tokens, this function determines which query should be - * ran. It also removes any special search tokens. - * - * @param aTokens - * An array of search tokens. - * @return an object with two properties: - * query: the correctly optimized, bound query to search the database - * with. - * tokens: the filtered list of tokens to search with. - */ - _getSearch: function PAC_getSearch(aTokens) - { - let foundToken = false; - let restrict = (behavior) => { - if (!foundToken) { - this._behavior = 0; - this._setBehavior("restrict"); - foundToken = true; - } - this._setBehavior(behavior); - }; - - // Set the proper behavior so our call to _getBoundSearchQuery gives us the - // correct query. - for (let i = aTokens.length - 1; i >= 0; i--) { - switch (aTokens[i]) { - case this._restrictHistoryToken: - restrict("history"); - break; - case this._restrictBookmarkToken: - restrict("bookmark"); - break; - case this._restrictTagToken: - restrict("tag"); - break; - case this._restrictOpenPageToken: - if (!this._enableActions) { - continue; - } - restrict("openpage"); - break; - case this._matchTitleToken: - restrict("title"); - break; - case this._matchURLToken: - restrict("url"); - break; - case this._restrictTypedToken: - restrict("typed"); - break; - default: - // We do not want to remove the token if we did not match. - continue; - } - - aTokens.splice(i, 1); - } - - // Set the right JavaScript behavior based on our preference. Note that the - // preference is whether or not we should filter JavaScript, and the - // behavior is if we should search it or not. - if (!this._filterJavaScript) { - this._setBehavior("javascript"); - } - - return { - query: this._getBoundSearchQuery(this._matchBehavior, aTokens), - tokens: aTokens - }; - }, - - /** - * @return a string consisting of the search query to be used based on the - * previously set urlbar suggestion preferences. - */ - _getSuggestionPrefQuery: function PAC_getSuggestionPrefQuery() - { - if (!this._hasBehavior("restrict") && this._hasBehavior("history") && - this._hasBehavior("bookmark")) { - return this._hasBehavior("typed") ? this._customQuery("AND h.typed = 1") - : this._defaultQuery; - } - let conditions = []; - if (this._hasBehavior("history")) { - // Enforce ignoring the visit_count index, since the frecency one is much - // faster in this case. ANALYZE helps the query planner to figure out the - // faster path, but it may not have up-to-date information yet. - conditions.push("+h.visit_count > 0"); - } - if (this._hasBehavior("typed")) { - conditions.push("h.typed = 1"); - } - if (this._hasBehavior("bookmark")) { - conditions.push("bookmarked"); - } - if (this._hasBehavior("tag")) { - conditions.push("tags NOTNULL"); - } - - return conditions.length ? this._customQuery("AND " + conditions.join(" AND ")) - : this._defaultQuery; - }, - - /** - * Obtains the search query to be used based on the previously set search - * behaviors (accessed by this._hasBehavior). The query is bound and ready to - * execute. - * - * @param aMatchBehavior - * How this query should match its tokens to the search string. - * @param aTokens - * An array of search tokens. - * @return the correctly optimized query to search the database with and the - * new list of tokens to search with. The query has all the needed - * parameters bound, so consumers can execute it without doing any - * additional work. - */ - _getBoundSearchQuery: function PAC_getBoundSearchQuery(aMatchBehavior, - aTokens) - { - let query = this._getSuggestionPrefQuery(); - - // Bind the needed parameters to the query so consumers can use it. - let params = query.params; - params.parent = PlacesUtils.tagsFolderId; - params.query_type = kQueryTypeFiltered; - params.matchBehavior = aMatchBehavior; - params.searchBehavior = this._behavior; - - // We only want to search the tokens that we are left with - not the - // original search string. - params.searchString = aTokens.join(" "); - - // Limit the query to the the maximum number of desired results. - // This way we can avoid doing more work than needed. - params.maxResults = this._maxRichResults; - - return query; - }, - - _getBoundOpenPagesQuery: function PAC_getBoundOpenPagesQuery(aTokens) - { - let query = this._openPagesQuery; - - // Bind the needed parameters to the query so consumers can use it. - let params = query.params; - params.query_type = kQueryTypeFiltered; - params.matchBehavior = this._matchBehavior; - params.searchBehavior = this._behavior; - - // We only want to search the tokens that we are left with - not the - // original search string. - params.searchString = aTokens.join(" "); - params.maxResults = this._maxRichResults; - - return query; - }, - - /** - * Obtains the keyword query with the properly bound parameters. - * - * @param aTokens - * The array of search tokens to check against. - * @return the bound keyword query. - */ - _getBoundKeywordQuery: function PAC_getBoundKeywordQuery(aTokens) - { - // The keyword is the first word in the search string, with the parameters - // following it. - let searchString = this._originalSearchString; - let queryString = ""; - let queryIndex = searchString.indexOf(" "); - if (queryIndex != -1) { - queryString = searchString.substring(queryIndex + 1); - } - // We need to escape the parameters as if they were the query in a URL - queryString = encodeURIComponent(queryString).replace(/%20/g, "+"); - - // The first word could be a keyword, so that's what we'll search. - let keyword = aTokens[0]; - - let query = this._keywordQuery; - let params = query.params; - params.keyword = keyword; - params.query_string = queryString; - params.query_type = kQueryTypeKeyword; - - return query; - }, - - /** - * Obtains the adaptive query with the properly bound parameters. - * - * @return the bound adaptive query. - */ - _getBoundAdaptiveQuery: function PAC_getBoundAdaptiveQuery(aMatchBehavior) - { - // If we were not given a match behavior, use the stored match behavior. - if (arguments.length == 0) { - aMatchBehavior = this._matchBehavior; - } - - let query = this._adaptiveQuery; - let params = query.params; - params.parent = PlacesUtils.tagsFolderId; - params.search_string = this._currentSearchString; - params.query_type = kQueryTypeFiltered; - params.matchBehavior = aMatchBehavior; - params.searchBehavior = this._behavior; - - return query; - }, - - /** - * Processes a mozIStorageRow to generate the proper data for the AutoComplete - * result. This will add an entry to the current result if it matches the - * criteria. - * - * @param aRow - * The row to process. - * @return true if the row is accepted, and false if not. - */ - _processRow: function PAC_processRow(aRow) - { - // Before we do any work, make sure this entry isn't already in our results. - let entryId = aRow.getResultByIndex(kQueryIndexPlaceId); - let escapedEntryURL = aRow.getResultByIndex(kQueryIndexURL); - let openPageCount = aRow.getResultByIndex(kQueryIndexOpenPageCount) || 0; - - // If actions are enabled and the page is open, add only the switch-to-tab - // result. Otherwise, add the normal result. - let [url, action] = this._enableActions && openPageCount > 0 && this._hasBehavior("openpage") ? - ["moz-action:switchtab," + escapedEntryURL, "action "] : - [escapedEntryURL, ""]; - - if (this._inResults(entryId, url)) { - return false; - } - - let entryTitle = aRow.getResultByIndex(kQueryIndexTitle) || ""; - let entryFavicon = aRow.getResultByIndex(kQueryIndexFaviconURL) || ""; - let entryBookmarked = aRow.getResultByIndex(kQueryIndexBookmarked); - let entryBookmarkTitle = entryBookmarked ? - aRow.getResultByIndex(kQueryIndexBookmarkTitle) : null; - let entryTags = aRow.getResultByIndex(kQueryIndexTags) || ""; - - // Always prefer the bookmark title unless it is empty - let title = entryBookmarkTitle || entryTitle; - - let style; - if (aRow.getResultByIndex(kQueryIndexQueryType) == kQueryTypeKeyword) { - style = "keyword"; - title = NetUtil.newURI(escapedEntryURL).host; - } - - // We will always prefer to show tags if we have them. - let showTags = !!entryTags; - - // However, we'll act as if a page is not bookmarked if the user wants - // only history and not bookmarks and there are no tags. - if (this._hasBehavior("history") && !this._hasBehavior("bookmark") && - !showTags) { - showTags = false; - style = "favicon"; - } - - // If we have tags and should show them, we need to add them to the title. - if (showTags) { - title += kTitleTagsSeparator + entryTags; - } - // We have to determine the right style to display. Tags show the tag icon, - // bookmarks get the bookmark icon, and keywords get the keyword icon. If - // the result does not fall into any of those, it just gets the favicon. - if (!style) { - // It is possible that we already have a style set (from a keyword - // search or because of the user's preferences), so only set it if we - // haven't already done so. - if (showTags) { - style = "tag"; - } - else if (entryBookmarked) { - style = "bookmark"; - } - else { - style = "favicon"; - } - } - - this._addToResults(entryId, url, title, entryFavicon, action + style); - return true; - }, - - /** - * Checks to see if the given place has already been added to the results. - * - * @param aPlaceId - * The place id to check for, may be null. - * @param aUrl - * The url to check for. - * @return true if the place has been added, false otherwise. - * - * @note Must check both the id and the url for a negative match, since - * autocomplete may run in the middle of a new page addition. In such - * a case the switch-to-tab query would hash the page by url, then a - * next query, running after the page addition, would hash it by id. - * It's not possible to just rely on url though, since keywords - * dynamically modify the url to include their search string. - */ - _inResults: function PAC_inResults(aPlaceId, aUrl) - { - if (aPlaceId && aPlaceId in this._usedPlaces) { - return true; - } - return aUrl in this._usedPlaces; - }, - - /** - * Adds a result to the AutoComplete results. Also tracks that we've added - * this place_id into the result set. - * - * @param aPlaceId - * The place_id of the item to be added to the result set. This is - * used by _inResults. - * @param aURISpec - * The URI spec for the entry. - * @param aTitle - * The title to give the entry. - * @param aFaviconSpec - * The favicon to give to the entry. - * @param aStyle - * Indicates how the entry should be styled when displayed. - */ - _addToResults: function PAC_addToResults(aPlaceId, aURISpec, aTitle, - aFaviconSpec, aStyle) - { - // Add this to our internal tracker to ensure duplicates do not end up in - // the result. _usedPlaces is an Object that is being used as a set. - // Not all entries have a place id, thus we fallback to the url for them. - // We cannot use only the url since keywords entries are modified to - // include the search string, and would be returned multiple times. Ids - // are faster too. - this._usedPlaces[aPlaceId || aURISpec] = true; - - // Obtain the favicon for this URI. - let favicon; - if (aFaviconSpec) { - let uri = NetUtil.newURI(aFaviconSpec); - favicon = PlacesUtils.favicons.getFaviconLinkForIcon(uri).spec; - } - favicon = favicon || PlacesUtils.favicons.defaultFavicon.spec; - - this._result.appendMatch(aURISpec, aTitle, favicon, aStyle); - }, - - /** - * Determines if the specified AutoComplete behavior is set. - * - * @param aType - * The behavior type to test for. - * @return true if the behavior is set, false otherwise. - */ - _hasBehavior: function PAC_hasBehavior(aType) - { - let behavior = Ci.mozIPlacesAutoComplete["BEHAVIOR_" + aType.toUpperCase()]; - - if (this._disablePrivateActions && - behavior == Ci.mozIPlacesAutoComplete.BEHAVIOR_OPENPAGE) { - return false; - } - - return this._behavior & behavior; - }, - - /** - * Enables the desired AutoComplete behavior. - * - * @param aType - * The behavior type to set. - */ - _setBehavior: function PAC_setBehavior(aType) - { - this._behavior |= - Ci.mozIPlacesAutoComplete["BEHAVIOR_" + aType.toUpperCase()]; - }, - - /** - * Determines if we are done searching or not. - * - * @return true if we have completed searching, false otherwise. - */ - isSearchComplete: function PAC_isSearchComplete() - { - // If _pendingQuery is null, we should no longer do any work since we have - // already called _finishSearch. This means we completed our search. - return this._pendingQuery == null; - }, - - /** - * Determines if the given handle of a pending statement is a pending search - * or not. - * - * @param aHandle - * A mozIStoragePendingStatement to check and see if we are waiting for - * results from it still. - * @return true if it is a pending query, false otherwise. - */ - isPendingSearch: function PAC_isPendingSearch(aHandle) - { - return this._pendingQuery == aHandle; - }, - - ////////////////////////////////////////////////////////////////////////////// - //// nsISupports - - classID: Components.ID("d0272978-beab-4adc-a3d4-04b76acfa4e7"), - - _xpcom_factory: XPCOMUtils.generateSingletonFactory(nsPlacesAutoComplete), - - QueryInterface: XPCOMUtils.generateQI([ - Ci.nsIAutoCompleteSearch, - Ci.nsIAutoCompleteSimpleResultListener, - Ci.mozIPlacesAutoComplete, - Ci.mozIStorageStatementCallback, - Ci.nsIObserver, - Ci.nsISupportsWeakReference, - ]) -}; - -var components = [nsPlacesAutoComplete]; -this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components); diff --git a/toolkit/components/places/nsPlacesAutoComplete.manifest b/toolkit/components/places/nsPlacesAutoComplete.manifest deleted file mode 100644 index 77dc732af23d..000000000000 --- a/toolkit/components/places/nsPlacesAutoComplete.manifest +++ /dev/null @@ -1,3 +0,0 @@ -component {d0272978-beab-4adc-a3d4-04b76acfa4e7} nsPlacesAutoComplete.js -contract @mozilla.org/autocomplete/search;1?name=history {d0272978-beab-4adc-a3d4-04b76acfa4e7} - diff --git a/toolkit/components/places/tests/autocomplete/.eslintrc b/toolkit/components/places/tests/autocomplete/.eslintrc deleted file mode 100644 index 8a895f93bd06..000000000000 --- a/toolkit/components/places/tests/autocomplete/.eslintrc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": [ - "../../../../../testing/xpcshell/xpcshell.eslintrc" - ] -} diff --git a/toolkit/components/places/tests/autocomplete/head_autocomplete.js b/toolkit/components/places/tests/autocomplete/head_autocomplete.js deleted file mode 100644 index ef6864ed1d10..000000000000 --- a/toolkit/components/places/tests/autocomplete/head_autocomplete.js +++ /dev/null @@ -1,314 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -var Ci = Components.interfaces; -var Cc = Components.classes; -var Cr = Components.results; -var Cu = Components.utils; - -Cu.import("resource://gre/modules/Services.jsm"); - -// Import common head. -{ - let commonFile = do_get_file("../head_common.js", false); - let uri = Services.io.newFileURI(commonFile); - Services.scriptloader.loadSubScript(uri.spec, this); -} - -// Put any other stuff relative to this test folder below. - - -/** - * Header file for autocomplete testcases that create a set of pages with uris, - * titles, tags and tests that a given search term matches certain pages. - */ - -var current_test = 0; - -function AutoCompleteInput(aSearches) { - this.searches = aSearches; -} -AutoCompleteInput.prototype = { - timeout: 10, - textValue: "", - searches: null, - searchParam: "", - popupOpen: false, - minResultsForPopup: 0, - invalidate: function() {}, - disableAutoComplete: false, - completeDefaultIndex: false, - get popup() { return this; }, - onSearchBegin: function() {}, - onSearchComplete: function() {}, - setSelectedIndex: function() {}, - get searchCount() { return this.searches.length; }, - getSearchAt: function(aIndex) { return this.searches[aIndex]; }, - QueryInterface: XPCOMUtils.generateQI([ - Ci.nsIAutoCompleteInput, - Ci.nsIAutoCompletePopup, - ]) -}; - -function toURI(aSpec) { - return uri(aSpec); -} - -var appendTags = true; -// Helper to turn off tag matching in results -function ignoreTags() -{ - print("Ignoring tags from results"); - appendTags = false; -} - -function ensure_results(aSearch, aExpected) -{ - let controller = Cc["@mozilla.org/autocomplete/controller;1"]. - getService(Ci.nsIAutoCompleteController); - - // Make an AutoCompleteInput that uses our searches - // and confirms results on search complete - let input = new AutoCompleteInput(["history"]); - - controller.input = input; - - if (typeof kSearchParam == "string") - input.searchParam = kSearchParam; - - let numSearchesStarted = 0; - input.onSearchBegin = function() { - numSearchesStarted++; - do_check_eq(numSearchesStarted, 1); - }; - - input.onSearchComplete = function() { - do_check_eq(numSearchesStarted, 1); - aExpected = aExpected.slice(); - - // Check to see the expected uris and titles match up (in any order) - for (let i = 0; i < controller.matchCount; i++) { - let value = controller.getValueAt(i); - let comment = controller.getCommentAt(i); - - print("Looking for '" + value + "', '" + comment + "' in expected results..."); - let j; - for (j = 0; j < aExpected.length; j++) { - // Skip processed expected results - if (aExpected[j] == undefined) - continue; - - let [uri, title, tags] = gPages[aExpected[j]]; - - // Load the real uri and titles and tags if necessary - uri = toURI(kURIs[uri]).spec; - title = kTitles[title]; - if (tags && appendTags) - title += " \u2013 " + tags.map(aTag => kTitles[aTag]); - print("Checking against expected '" + uri + "', '" + title + "'..."); - - // Got a match on both uri and title? - if (uri == value && title == comment) { - print("Got it at index " + j + "!!"); - // Make it undefined so we don't process it again - aExpected[j] = undefined; - break; - } - } - - // We didn't hit the break, so we must have not found it - if (j == aExpected.length) - do_throw("Didn't find the current result ('" + value + "', '" + comment + "') in expected: " + aExpected); - } - - // Make sure we have the right number of results - print("Expecting " + aExpected.length + " results; got " + - controller.matchCount + " results"); - do_check_eq(controller.matchCount, aExpected.length); - - // If we expect results, make sure we got matches - do_check_eq(controller.searchStatus, aExpected.length ? - Ci.nsIAutoCompleteController.STATUS_COMPLETE_MATCH : - Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH); - - // Fetch the next test if we have more - if (++current_test < gTests.length) - run_test(); - - do_test_finished(); - }; - - print("Searching for.. '" + aSearch + "'"); - controller.startSearch(aSearch); -} - -// Get history services -var histsvc = Cc["@mozilla.org/browser/nav-history-service;1"]. - getService(Ci.nsINavHistoryService); -var bhist = histsvc.QueryInterface(Ci.nsIBrowserHistory); -var bmsvc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"]. - getService(Ci.nsINavBookmarksService); -var tagsvc = Cc["@mozilla.org/browser/tagging-service;1"]. - getService(Ci.nsITaggingService); -var iosvc = Cc["@mozilla.org/network/io-service;1"]. - getService(Ci.nsIIOService); -var prefs = Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefBranch); - -// Some date not too long ago -var gDate = new Date(Date.now() - 1000 * 60 * 60) * 1000; -// Store the page info for each uri -var gPages = []; - -// Initialization tasks to be run before the next test -var gNextTestSetupTasks = []; - -/** - * Adds a page, and creates various properties for it depending on the - * parameters passed in. This function will also add one visit, unless - * aNoVisit is true. - * - * @param aURI - * An index into kURIs that holds the string for the URI we are to add a - * page for. - * @param aTitle - * An index into kTitles that holds the string for the title we are to - * associate with the specified URI. - * @param aBook [optional] - * An index into kTitles that holds the string for the title we are to - * associate with the bookmark. If this is undefined, no bookmark is - * created. - * @param aTags [optional] - * An array of indexes into kTitles that hold the strings for the tags we - * are to associate with the URI. If this is undefined (or aBook is), no - * tags are added. - * @param aKey [optional] - * A string to associate as the keyword for this bookmark. aBook must be - * a valid index into kTitles for this to be checked and used. - * @param aTransitionType [optional] - * The transition type to use when adding the visit. The default is - * nsINavHistoryService::TRANSITION_LINK. - * @param aNoVisit [optional] - * If true, no visit is added for the URI. If false or undefined, a - * visit is added. - */ -function addPageBook(aURI, aTitle, aBook, aTags, aKey, aTransitionType, aNoVisit) -{ - gNextTestSetupTasks.push([task_addPageBook, arguments]); -} - -function* task_addPageBook(aURI, aTitle, aBook, aTags, aKey, aTransitionType, aNoVisit) -{ - // Add a page entry for the current uri - gPages[aURI] = [aURI, aBook != undefined ? aBook : aTitle, aTags]; - - let uri = toURI(kURIs[aURI]); - let title = kTitles[aTitle]; - - let out = [aURI, aTitle, aBook, aTags, aKey]; - out.push("\nuri=" + kURIs[aURI]); - out.push("\ntitle=" + title); - - // Add the page and a visit if we need to - if (!aNoVisit) { - yield PlacesTestUtils.addVisits({ - uri: uri, - transition: aTransitionType || TRANSITION_LINK, - visitDate: gDate, - title: title - }); - out.push("\nwith visit"); - } - - // Add a bookmark if we need to - if (aBook != undefined) { - let book = kTitles[aBook]; - let bmid = bmsvc.insertBookmark(bmsvc.unfiledBookmarksFolder, uri, - bmsvc.DEFAULT_INDEX, book); - out.push("\nbook=" + book); - - // Add a keyword to the bookmark if we need to - if (aKey != undefined) - yield PlacesUtils.keywords.insert({url: uri.spec, keyword: aKey}); - - // Add tags if we need to - if (aTags != undefined && aTags.length > 0) { - // Convert each tag index into the title - let tags = aTags.map(aTag => kTitles[aTag]); - tagsvc.tagURI(uri, tags); - out.push("\ntags=" + tags); - } - } - - print("\nAdding page/book/tag: " + out.join(", ")); -} - -function run_test() { - print("\n"); - // always search in history + bookmarks, no matter what the default is - prefs.setBoolPref("browser.urlbar.suggest.history", true); - prefs.setBoolPref("browser.urlbar.suggest.bookmark", true); - prefs.setBoolPref("browser.urlbar.suggest.openpage", true); - prefs.setBoolPref("browser.urlbar.suggest.history.onlyTyped", false); - - // Search is asynchronous, so don't let the test finish immediately - do_test_pending(); - - // Load the test and print a description then run the test - let [description, search, expected, func] = gTests[current_test]; - print(description); - - // By default assume we want to match tags - appendTags = true; - - // Do an extra function if necessary - if (func) - func(); - - Task.spawn(function* () { - // Iterate over all tasks and execute them - for (let [fn, args] of gNextTestSetupTasks) { - yield fn.apply(this, args); - } - - // Clean up to allow tests to register more functions. - gNextTestSetupTasks = []; - - // At this point frecency could still be updating due to latest pages - // updates. This is not a problem in real life, but autocomplete tests - // should return reliable resultsets, thus we have to wait. - yield PlacesTestUtils.promiseAsyncUpdates(); - - }).then(() => ensure_results(search, expected), - do_report_unexpected_exception); -} - -// Utility function to remove history pages -function removePages(aURIs) -{ - gNextTestSetupTasks.push([do_removePages, arguments]); -} - -function do_removePages(aURIs) -{ - for (let uri of aURIs) - histsvc.removePage(toURI(kURIs[uri])); -} - -// Utility function to mark pages as typed -function markTyped(aURIs, aTitle) -{ - gNextTestSetupTasks.push([task_markTyped, arguments]); -} - -function* task_markTyped(aURIs, aTitle) -{ - for (let uri of aURIs) { - yield PlacesTestUtils.addVisits({ - uri: toURI(kURIs[uri]), - transition: TRANSITION_TYPED, - title: kTitles[aTitle] - }); - } -} diff --git a/toolkit/components/places/tests/autocomplete/test_416211.js b/toolkit/components/places/tests/autocomplete/test_416211.js deleted file mode 100644 index 8f662b5b13fc..000000000000 --- a/toolkit/components/places/tests/autocomplete/test_416211.js +++ /dev/null @@ -1,30 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* - * Test bug 416211 to make sure results that match the tag show the bookmark - * title instead of the page title. - */ - -var theTag = "superTag"; - -// Define some shared uris and titles (each page needs its own uri) -var kURIs = [ - "http://theuri/", -]; -var kTitles = [ - "Page title", - "Bookmark title", - theTag, -]; - -// Add page with a title, bookmark, and [tags] -addPageBook(0, 0, 1, [2]); - -// Provide for each test: description; search terms; array of gPages indices of -// pages that should match; optional function to be run before the test -var gTests = [ - ["0: Make sure the tag match gives the bookmark title", - theTag, [0]], -]; diff --git a/toolkit/components/places/tests/autocomplete/test_416214.js b/toolkit/components/places/tests/autocomplete/test_416214.js deleted file mode 100644 index f8911800691a..000000000000 --- a/toolkit/components/places/tests/autocomplete/test_416214.js +++ /dev/null @@ -1,38 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* - * Test autocomplete for non-English URLs that match the tag bug 416214. Also - * test bug 417441 by making sure escaped ascii characters like "+" remain - * escaped. - * - * - add a visit for a page with a non-English URL - * - add a tag for the page - * - search for the tag - * - test number of matches (should be exactly one) - * - make sure the url is decoded - */ - -var theTag = "superTag"; - -// Define some shared uris and titles (each page needs its own uri) -var kURIs = [ - "http://escaped/ユニコード", - "http://asciiescaped/blocking-firefox3%2B", -]; -var kTitles = [ - "title", - theTag, -]; - -// Add pages that match the tag -addPageBook(0, 0, 0, [1]); -addPageBook(1, 0, 0, [1]); - -// Provide for each test: description; search terms; array of gPages indices of -// pages that should match; optional function to be run before the test -var gTests = [ - ["0: Make sure tag matches return the right url as well as '+' remain escaped", - theTag, [0, 1]], -]; diff --git a/toolkit/components/places/tests/autocomplete/test_417798.js b/toolkit/components/places/tests/autocomplete/test_417798.js deleted file mode 100644 index 6306c4125c81..000000000000 --- a/toolkit/components/places/tests/autocomplete/test_417798.js +++ /dev/null @@ -1,36 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * Test for bug 417798 to make sure javascript: URIs don't show up unless the - * user searches for javascript: explicitly. - */ - -// Define some shared uris and titles (each page needs its own uri) -var kURIs = [ - "http://abc/def", - "javascript:5", -]; -var kTitles = [ - "Title with javascript:", -]; - -addPageBook(0, 0); // regular url -// javascript: uri as bookmark (no visit) -addPageBook(1, 0, 0, undefined, undefined, undefined, true); - -// Provide for each test: description; search terms; array of gPages indices of -// pages that should match; optional function to be run before the test -var gTests = [ - ["0: Match non-javascript: with plain search", - "a", [0]], - ["1: Match non-javascript: with almost javascript:", - "javascript", [0]], - ["2: Match javascript:", - "javascript:", [0, 1]], - ["3: Match nothing with non-first javascript:", - "5 javascript:", []], - ["4: Match javascript: with multi-word search", - "javascript: 5", [1]], -]; diff --git a/toolkit/components/places/tests/autocomplete/test_418257.js b/toolkit/components/places/tests/autocomplete/test_418257.js deleted file mode 100644 index edff19d8b0f0..000000000000 --- a/toolkit/components/places/tests/autocomplete/test_418257.js +++ /dev/null @@ -1,43 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * Test bug 418257 by making sure tags are returned with the title as part of - * the "comment" if there are tags even if we didn't match in the tags. They - * are separated from the title by a endash. - */ - -// Define some shared uris and titles (each page needs its own uri) -var kURIs = [ - "http://page1", - "http://page2", - "http://page3", - "http://page4", -]; -var kTitles = [ - "tag1", - "tag2", - "tag3", -]; - -// Add pages with varying number of tags -addPageBook(0, 0, 0, [0]); -addPageBook(1, 0, 0, [0, 1]); -addPageBook(2, 0, 0, [0, 2]); -addPageBook(3, 0, 0, [0, 1, 2]); - -// Provide for each test: description; search terms; array of gPages indices of -// pages that should match; optional function to be run before the test -var gTests = [ - ["0: Make sure tags come back in the title when matching tags", - "page1 tag", [0]], - ["1: Check tags in title for page2", - "page2 tag", [1]], - ["2: Make sure tags appear even when not matching the tag", - "page3", [2]], - ["3: Multiple tags come in commas for page4", - "page4", [3]], - ["4: Extra test just to make sure we match the title", - "tag2", [1, 3]], -]; diff --git a/toolkit/components/places/tests/autocomplete/test_422277.js b/toolkit/components/places/tests/autocomplete/test_422277.js deleted file mode 100644 index d6eb193dc8f0..000000000000 --- a/toolkit/components/places/tests/autocomplete/test_422277.js +++ /dev/null @@ -1,25 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * Test bug 422277 to make sure bad escaped uris don't get escaped. This makes - * sure we don't hit an assertion for "not a UTF8 string". - */ - -// Define some shared uris and titles (each page needs its own uri) -var kURIs = [ - "http://site/%EAid", -]; -var kTitles = [ - "title", -]; - -addPageBook(0, 0); - -// Provide for each test: description; search terms; array of gPages indices of -// pages that should match; optional function to be run before the test -var gTests = [ - ["0: Bad escaped uri stays escaped", - "site", [0]], -]; diff --git a/toolkit/components/places/tests/autocomplete/test_autocomplete_on_value_removed_479089.js b/toolkit/components/places/tests/autocomplete/test_autocomplete_on_value_removed_479089.js deleted file mode 100644 index 8c9b31cdbbba..000000000000 --- a/toolkit/components/places/tests/autocomplete/test_autocomplete_on_value_removed_479089.js +++ /dev/null @@ -1,54 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* - * Need to test that removing a page from autocomplete actually removes a page - * Description From Shawn Wilsher :sdwilsh 2009-02-18 11:29:06 PST - * We don't test the code path of onValueRemoved - * for the autocomplete implementation - * Bug 479089 - */ - -var histsvc = Cc["@mozilla.org/browser/nav-history-service;1"]. -getService(Ci.nsINavHistoryService); - -function run_test() -{ - run_next_test(); -} - -add_task(function* test_autocomplete_on_value_removed() -{ - // QI to nsIAutoCompleteSimpleResultListener - var listener = Cc["@mozilla.org/autocomplete/search;1?name=history"]. - getService(Components.interfaces.nsIAutoCompleteSimpleResultListener); - - // add history visit - var testUri = uri("http://foo.mozilla.com/"); - yield PlacesTestUtils.addVisits({ - uri: testUri, - referrer: uri("http://mozilla.com/") - }); - // create a query object - var query = histsvc.getNewQuery(); - // create the options object we will never use - var options = histsvc.getNewQueryOptions(); - // look for this uri only - query.uri = testUri; - // execute - var queryRes = histsvc.executeQuery(query, options); - // open the result container - queryRes.root.containerOpen = true; - // debug queries - // dump_table("moz_places"); - do_check_eq(queryRes.root.childCount, 1); - // call the untested code path - listener.onValueRemoved(null, testUri.spec, true); - // make sure it is GONE from the DB - do_check_eq(queryRes.root.childCount, 0); - // close the container - queryRes.root.containerOpen = false; -}); diff --git a/toolkit/components/places/tests/autocomplete/test_download_embed_bookmarks.js b/toolkit/components/places/tests/autocomplete/test_download_embed_bookmarks.js deleted file mode 100644 index 65bec60cc787..000000000000 --- a/toolkit/components/places/tests/autocomplete/test_download_embed_bookmarks.js +++ /dev/null @@ -1,53 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- - * vim:set ts=2 sw=2 sts=2 et: - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * Tests bug 449406 to ensure that TRANSITION_DOWNLOAD, TRANSITION_EMBED and - * TRANSITION_FRAMED_LINK bookmarked uri's show up in the location bar. - */ - -// Define some shared uris and titles (each page needs its own uri) -var kURIs = [ - "http://download/bookmarked", - "http://embed/bookmarked", - "http://framed/bookmarked", - "http://download", - "http://embed", - "http://framed", -]; -var kTitles = [ - "download-bookmark", - "embed-bookmark", - "framed-bookmark", - "download2", - "embed2", - "framed2", -]; - -// Add download and embed uris -addPageBook(0, 0, 0, undefined, undefined, TRANSITION_DOWNLOAD); -addPageBook(1, 1, 1, undefined, undefined, TRANSITION_EMBED); -addPageBook(2, 2, 2, undefined, undefined, TRANSITION_FRAMED_LINK); -addPageBook(3, 3, undefined, undefined, undefined, TRANSITION_DOWNLOAD); -addPageBook(4, 4, undefined, undefined, undefined, TRANSITION_EMBED); -addPageBook(5, 5, undefined, undefined, undefined, TRANSITION_FRAMED_LINK); - -// Provide for each test: description; search terms; array of gPages indices of -// pages that should match; optional function to be run before the test -var gTests = [ - ["0: Searching for bookmarked download uri matches", - kTitles[0], [0]], - ["1: Searching for bookmarked embed uri matches", - kTitles[1], [1]], - ["2: Searching for bookmarked framed uri matches", - kTitles[2], [2]], - ["3: Searching for download uri does not match", - kTitles[3], []], - ["4: Searching for embed uri does not match", - kTitles[4], []], - ["5: Searching for framed uri does not match", - kTitles[5], []], -]; diff --git a/toolkit/components/places/tests/autocomplete/test_empty_search.js b/toolkit/components/places/tests/autocomplete/test_empty_search.js deleted file mode 100644 index df8eac383a7e..000000000000 --- a/toolkit/components/places/tests/autocomplete/test_empty_search.js +++ /dev/null @@ -1,69 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * Test for bug 426864 that makes sure the empty search (drop down list) only - * shows typed pages from history. - */ - -// Define some shared uris and titles (each page needs its own uri) -var kURIs = [ - "http://foo/0", - "http://foo/1", - "http://foo/2", - "http://foo/3", - "http://foo/4", - "http://foo/5", -]; -var kTitles = [ - "title", -]; - -// Visited (in history) -addPageBook(0, 0); // history -addPageBook(1, 0, 0); // bookmark -addPageBook(2, 0); // history typed -addPageBook(3, 0, 0); // bookmark typed - -// Unvisited bookmark -addPageBook(4, 0, 0); // bookmark -addPageBook(5, 0, 0); // bookmark typed - -// Set some pages as typed -markTyped([2, 3, 5], 0); -// Remove pages from history to treat them as unvisited -removePages([4, 5]); - -// Provide for each test: description; search terms; array of gPages indices of -// pages that should match; optional function to be run before the test -var gTests = [ - ["0: Match everything", - "foo", [0, 1, 2, 3, 4, 5]], - ["1: Match only typed history", - "foo ^ ~", [2, 3]], - ["2: Drop-down empty search matches only typed history", - "", [2, 3]], - ["3: Drop-down empty search matches only bookmarks", - "", [2, 3], matchBookmarks], - ["4: Drop-down empty search matches only typed", - "", [2, 3], matchTyped], -]; - -function matchBookmarks() { - prefs.setBoolPref("browser.urlbar.suggest.history", false); - prefs.setBoolPref("browser.urlbar.suggest.bookmark", true); - clearPrefs(); -} - -function matchTyped() { - prefs.setBoolPref("browser.urlbar.suggest.history", true); - prefs.setBoolPref("browser.urlbar.suggest.history.onlyTyped", true); - clearPrefs(); -} - -function clearPrefs() { - prefs.clearUserPref("browser.urlbar.suggest.history"); - prefs.clearUserPref("browser.urlbar.suggest.bookmark"); - prefs.clearUserPref("browser.urlbar.suggest.history.onlyTyped"); -} diff --git a/toolkit/components/places/tests/autocomplete/test_enabled.js b/toolkit/components/places/tests/autocomplete/test_enabled.js deleted file mode 100644 index 80fc4a136df7..000000000000 --- a/toolkit/components/places/tests/autocomplete/test_enabled.js +++ /dev/null @@ -1,69 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * Test for bug 471903 to make sure searching in autocomplete can be turned on - * and off. Also test bug 463535 for pref changing search. - */ - -// Define some shared uris and titles (each page needs its own uri) -var kURIs = [ - "http://url/0", -]; -var kTitles = [ - "title", -]; - -addPageBook(0, 0); // visited page - -// Provide for each test: description; search terms; array of gPages indices of -// pages that should match; optional function to be run before the test -var gTests = [ - ["1: plain search", - "url", [0]], - ["2: search disabled", - "url", [], () => setSearch(0)], - ["3: resume normal search", - "url", [0], () => setSearch(1)], -]; - -function setSearch(aSearch) { - prefs.setBoolPref("browser.urlbar.autocomplete.enabled", !!aSearch); -} - -add_task(function* test_sync_enabled() { - // Initialize autocomplete component. - Cc["@mozilla.org/autocomplete/search;1?name=history"] - .getService(Ci.mozIPlacesAutoComplete); - - let types = [ "history", "bookmark", "openpage" ]; - - // Test the service keeps browser.urlbar.autocomplete.enabled synchronized - // with browser.urlbar.suggest prefs. - for (let type of types) { - Services.prefs.setBoolPref("browser.urlbar.suggest." + type, true); - } - Assert.equal(Services.prefs.getBoolPref("browser.urlbar.autocomplete.enabled"), true); - - // Disable autocomplete and check all the suggest prefs are set to false. - Services.prefs.setBoolPref("browser.urlbar.autocomplete.enabled", false); - for (let type of types) { - Assert.equal(Services.prefs.getBoolPref("browser.urlbar.suggest." + type), false); - } - - // Setting even a single suggest pref to true should enable autocomplete. - Services.prefs.setBoolPref("browser.urlbar.suggest.history", true); - for (let type of types.filter(t => t != "history")) { - Assert.equal(Services.prefs.getBoolPref("browser.urlbar.suggest." + type), false); - } - Assert.equal(Services.prefs.getBoolPref("browser.urlbar.autocomplete.enabled"), true); - - // Disable autocoplete again, then re-enable it and check suggest prefs - // have been reset. - Services.prefs.setBoolPref("browser.urlbar.autocomplete.enabled", false); - Services.prefs.setBoolPref("browser.urlbar.autocomplete.enabled", true); - for (let type of types.filter(t => t != "history")) { - Assert.equal(Services.prefs.getBoolPref("browser.urlbar.suggest." + type), true); - } -}); diff --git a/toolkit/components/places/tests/autocomplete/test_escape_self.js b/toolkit/components/places/tests/autocomplete/test_escape_self.js deleted file mode 100644 index 0b0918b8ffe2..000000000000 --- a/toolkit/components/places/tests/autocomplete/test_escape_self.js +++ /dev/null @@ -1,30 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * Test bug 422698 to make sure searches with urls from the location bar - * correctly match itself when it contains escaped characters. - */ - -// Define some shared uris and titles (each page needs its own uri) -var kURIs = [ - "http://unescapeduri/", - "http://escapeduri/%40/", -]; -var kTitles = [ - "title", -]; - -// Add unescaped and escaped uris -addPageBook(0, 0); -addPageBook(1, 0); - -// Provide for each test: description; search terms; array of gPages indices of -// pages that should match; optional function to be run before the test -var gTests = [ - ["0: Unescaped location matches itself", - kURIs[0], [0]], - ["1: Escaped location matches itself", - kURIs[1], [1]], -]; diff --git a/toolkit/components/places/tests/autocomplete/test_ignore_protocol.js b/toolkit/components/places/tests/autocomplete/test_ignore_protocol.js deleted file mode 100644 index 2ad63b735f42..000000000000 --- a/toolkit/components/places/tests/autocomplete/test_ignore_protocol.js +++ /dev/null @@ -1,27 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * Test bug 424509 to make sure searching for "h" doesn't match "http" of urls. - */ - -// Define some shared uris and titles (each page needs its own uri) -var kURIs = [ - "http://site/", - "http://happytimes/", -]; -var kTitles = [ - "title", -]; - -// Add site without "h" and with "h" -addPageBook(0, 0); -addPageBook(1, 0); - -// Provide for each test: description; search terms; array of gPages indices of -// pages that should match; optional function to be run before the test -var gTests = [ - ["0: Searching for h matches site and not http://", - "h", [1]], -]; diff --git a/toolkit/components/places/tests/autocomplete/test_keyword_search.js b/toolkit/components/places/tests/autocomplete/test_keyword_search.js deleted file mode 100644 index 796f386bb826..000000000000 --- a/toolkit/components/places/tests/autocomplete/test_keyword_search.js +++ /dev/null @@ -1,73 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * Test for bug 392143 that puts keyword results into the autocomplete. Makes - * sure that multiple parameter queries get spaces converted to +, + converted - * to %2B, non-ascii become escaped, and pages in history that match the - * keyword uses the page's title. - * - * Also test for bug 249468 by making sure multiple keyword bookmarks with the - * same keyword appear in the list. - */ - -// Details for the keyword bookmark -var keyBase = "http://abc/?search="; -var keyKey = "key"; - -// A second keyword bookmark with the same keyword -var otherBase = "http://xyz/?foo="; - -var unescaped = "ユニコード"; -var pageInHistory = "ThisPageIsInHistory"; - -// Define some shared uris and titles (each page needs its own uri) -var kURIs = [ - keyBase + "%s", - keyBase + "term", - keyBase + "multi+word", - keyBase + "blocking%2B", - keyBase + unescaped, - keyBase + pageInHistory, - keyBase, - otherBase + "%s", - keyBase + "twoKey", - otherBase + "twoKey" -]; -var kTitles = [ - "Generic page title", - "Keyword title", - "abc", - "xyz" -]; - -// Add the keyword bookmark -addPageBook(0, 0, 1, [], keyKey); -// Add in the "fake pages" for keyword searches -gPages[1] = [1, 2]; -gPages[2] = [2, 2]; -gPages[3] = [3, 2]; -gPages[4] = [4, 2]; -// Add a page into history -addPageBook(5, 2); -gPages[6] = [6, 2]; - -// Provide for each test: description; search terms; array of gPages indices of -// pages that should match; optional function to be run before the test -var gTests = [ - ["0: Plain keyword query", - keyKey + " term", [1]], - ["1: Multi-word keyword query", - keyKey + " multi word", [2]], - ["2: Keyword query with +", - keyKey + " blocking+", [3]], - ["3: Unescaped term in query", - keyKey + " " + unescaped, [4]], - ["4: Keyword that happens to match a page", - keyKey + " " + pageInHistory, [5]], - ["5: Keyword without query (without space)", - keyKey, [6]], - ["6: Keyword without query (with space)", - keyKey + " ", [6]], -]; diff --git a/toolkit/components/places/tests/autocomplete/test_match_beginning.js b/toolkit/components/places/tests/autocomplete/test_match_beginning.js deleted file mode 100644 index b9ba3ab39b1c..000000000000 --- a/toolkit/components/places/tests/autocomplete/test_match_beginning.js +++ /dev/null @@ -1,45 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * Test bug 451760 which allows matching only at the beginning of urls or - * titles to simulate Firefox 2 functionality. - */ - -// Define some shared uris and titles (each page needs its own uri) -var kURIs = [ - "http://x.com/y", - "https://y.com/x", -]; -var kTitles = [ - "a b", - "b a", -]; - -addPageBook(0, 0); -addPageBook(1, 1); - -// Provide for each test: description; search terms; array of gPages indices of -// pages that should match; optional function to be run before the test -var gTests = [ - // Tests after this one will match at the beginning - ["0: Match at the beginning of titles", - "a", [0], - () => setBehavior(3)], - ["1: Match at the beginning of titles", - "b", [1]], - ["2: Match at the beginning of urls", - "x", [0]], - ["3: Match at the beginning of urls", - "y", [1]], - - // Tests after this one will match against word boundaries and anywhere - ["4: Sanity check that matching anywhere finds more", - "a", [0, 1], - () => setBehavior(1)], -]; - -function setBehavior(aType) { - prefs.setIntPref("browser.urlbar.matchBehavior", aType); -} diff --git a/toolkit/components/places/tests/autocomplete/test_multi_word_search.js b/toolkit/components/places/tests/autocomplete/test_multi_word_search.js deleted file mode 100644 index c0b896c8687f..000000000000 --- a/toolkit/components/places/tests/autocomplete/test_multi_word_search.js +++ /dev/null @@ -1,49 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * Test for bug 401869 to allow multiple words separated by spaces to match in - * the page title, page url, or bookmark title to be considered a match. All - * terms must match but not all terms need to be in the title, etc. - * - * Test bug 424216 by making sure bookmark titles are always shown if one is - * available. Also bug 425056 makes sure matches aren't found partially in the - * page title and partially in the bookmark. - */ - -// Define some shared uris and titles (each page needs its own uri) -var kURIs = [ - "http://a.b.c/d-e_f/h/t/p", - "http://d.e.f/g-h_i/h/t/p", - "http://g.h.i/j-k_l/h/t/p", - "http://j.k.l/m-n_o/h/t/p", -]; -var kTitles = [ - "f(o)o br", - "b(a)r bz", -]; - -// Regular pages -addPageBook(0, 0); -addPageBook(1, 1); -// Bookmarked pages -addPageBook(2, 0, 0); -addPageBook(3, 0, 1); - -// Provide for each test: description; search terms; array of gPages indices of -// pages that should match; optional function to be run before the test -var gTests = [ - ["0: Match 2 terms all in url", - "c d", [0]], - ["1: Match 1 term in url and 1 term in title", - "b e", [0, 1]], - ["2: Match 3 terms all in title; display bookmark title if matched", - "b a z", [1, 3]], - ["3: Match 2 terms in url and 1 in title; make sure bookmark title is used for search", - "k f t", [2]], - ["4: Match 3 terms in url and 1 in title", - "d i g z", [1]], - ["5: Match nothing", - "m o z i", []], -]; diff --git a/toolkit/components/places/tests/autocomplete/test_special_search.js b/toolkit/components/places/tests/autocomplete/test_special_search.js deleted file mode 100644 index 78bf5a7d6413..000000000000 --- a/toolkit/components/places/tests/autocomplete/test_special_search.js +++ /dev/null @@ -1,183 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * Test for bug 395161 that allows special searches that restrict results to - * history/bookmark/tagged items and title/url matches. - * - * Test 485122 by making sure results don't have tags when restricting result - * to just history either by default behavior or dynamic query restrict. - */ - -// Define some shared uris and titles (each page needs its own uri) -var kURIs = [ - "http://url/", - "http://url/2", - "http://foo.bar/", - "http://foo.bar/2", - "http://url/star", - "http://url/star/2", - "http://foo.bar/star", - "http://foo.bar/star/2", - "http://url/tag", - "http://url/tag/2", - "http://foo.bar/tag", - "http://foo.bar/tag/2", -]; -var kTitles = [ - "title", - "foo.bar", -]; - -// Plain page visits -addPageBook(0, 0); // plain page -addPageBook(1, 1); // title -addPageBook(2, 0); // url -addPageBook(3, 1); // title and url - -// Bookmarked pages (no tag) -addPageBook(4, 0, 0); // bookmarked page -addPageBook(5, 1, 1); // title -addPageBook(6, 0, 0); // url -addPageBook(7, 1, 1); // title and url - -// Tagged pages -addPageBook(8, 0, 0, [1]); // tagged page -addPageBook(9, 1, 1, [1]); // title -addPageBook(10, 0, 0, [1]); // url -addPageBook(11, 1, 1, [1]); // title and url - -// Remove pages from history to treat them as unvisited, so pages that do have -// visits are 0,1,2,3,5,10 -removePages([4, 6, 7, 8, 9, 11]); -// Set some pages as typed -markTyped([0, 10], 0); -markTyped([3], 1); - -// Provide for each test: description; search terms; array of gPages indices of -// pages that should match; optional function to be run before the test -var gTests = [ - // Test restricting searches - ["0: History restrict", - "^", [0, 1, 2, 3, 5, 10]], - ["1: Star restrict", - "*", [4, 5, 6, 7, 8, 9, 10, 11]], - ["2: Tag restrict", - "+", [8, 9, 10, 11]], - - // Test specials as any word position - ["3: Special as first word", - "^ foo bar", [1, 2, 3, 5, 10]], - ["4: Special as middle word", - "foo ^ bar", [1, 2, 3, 5, 10]], - ["5: Special as last word", - "foo bar ^", [1, 2, 3, 5, 10]], - - // Test restricting and matching searches with a term - ["6.1: foo ^ -> history", - "foo ^", [1, 2, 3, 5, 10]], - ["6.2: foo | -> history (change pref)", - "foo |", [1, 2, 3, 5, 10], () => changeRestrict("history", "|")], - ["7.1: foo * -> is star", - "foo *", [5, 6, 7, 8, 9, 10, 11], () => resetRestrict("history")], - ["7.2: foo | -> is star (change pref)", - "foo |", [5, 6, 7, 8, 9, 10, 11], () => changeRestrict("bookmark", "|")], - ["8.1: foo # -> in title", - "foo #", [1, 3, 5, 7, 8, 9, 10, 11], () => resetRestrict("bookmark")], - ["8.2: foo | -> in title (change pref)", - "foo |", [1, 3, 5, 7, 8, 9, 10, 11], () => changeRestrict("title", "|")], - ["9.1: foo @ -> in url", - "foo @", [2, 3, 6, 7, 10, 11], () => resetRestrict("title")], - ["9.2: foo | -> in url (change pref)", - "foo |", [2, 3, 6, 7, 10, 11], () => changeRestrict("url", "|")], - ["10: foo + -> is tag", - "foo +", [8, 9, 10, 11], () => resetRestrict("url")], - ["10.2: foo | -> is tag (change pref)", - "foo |", [8, 9, 10, 11], () => changeRestrict("tag", "|")], - ["10.3: foo ~ -> is typed", - "foo ~", [3, 10], () => resetRestrict("tag")], - ["10.4: foo | -> is typed (change pref)", - "foo |", [3, 10], () => changeRestrict("typed", "|")], - - // Test various pairs of special searches - ["11: foo ^ * -> history, is star", - "foo ^ *", [5, 10], () => resetRestrict("typed")], - ["12: foo ^ # -> history, in title", - "foo ^ #", [1, 3, 5, 10]], - ["13: foo ^ @ -> history, in url", - "foo ^ @", [2, 3, 10]], - ["14: foo ^ + -> history, is tag", - "foo ^ +", [10]], - ["14.1: foo ^ ~ -> history, is typed", - "foo ^ ~", [3, 10]], - ["15: foo * # -> is star, in title", - "foo * #", [5, 7, 8, 9, 10, 11]], - ["16: foo * @ -> is star, in url", - "foo * @", [6, 7, 10, 11]], - ["17: foo * + -> same as +", - "foo * +", [8, 9, 10, 11]], - ["17.1: foo * ~ -> is star, is typed", - "foo * ~", [10]], - ["18: foo # @ -> in title, in url", - "foo # @", [3, 7, 10, 11]], - ["19: foo # + -> in title, is tag", - "foo # +", [8, 9, 10, 11]], - ["19.1: foo # ~ -> in title, is typed", - "foo # ~", [3, 10]], - ["20: foo @ + -> in url, is tag", - "foo @ +", [10, 11]], - ["20.1: foo @ ~ -> in url, is typed", - "foo @ ~", [3, 10]], - ["20.2: foo + ~ -> is tag, is typed", - "foo + ~", [10]], - - // Test default usage by setting certain bits of default.behavior to 1 - ["21: foo -> default history", - "foo", [1, 2, 3, 5, 10], function () { setPref({ history: true }); }], - ["22: foo -> default history or is star", - "foo", [1, 2, 3, 5, 6, 7, 8, 9, 10, 11], () => setPref({ history: true, bookmark: true })], - ["22.1: foo -> default history or is star, is typed", - "foo", [3, 10], () => setPref({ history: true, bookmark: true, "history.onlyTyped": true })], - -]; - -function setPref(aTypes) { - clearSuggestPrefs(); - for (let type in aTypes) { - prefs.setBoolPref("browser.urlbar.suggest." + type, aTypes[type]); - } -} - -function clearSuggestPrefs() { - prefs.setBoolPref("browser.urlbar.suggest.history", false); - prefs.setBoolPref("browser.urlbar.suggest.bookmark", false); - prefs.setBoolPref("browser.urlbar.suggest.history.onlyTyped", false); - prefs.setBoolPref("browser.urlbar.suggest.openpage", false); -} - -function changeRestrict(aType, aChar) -{ - let branch = "browser.urlbar."; - // "title" and "url" are different from everything else, so special case them. - if (aType == "title" || aType == "url") - branch += "match."; - else - branch += "restrict."; - - print("changing restrict for " + aType + " to '" + aChar + "'"); - prefs.setCharPref(branch + aType, aChar); -} - -function resetRestrict(aType) -{ - let branch = "browser.urlbar."; - // "title" and "url" are different from everything else, so special case them. - if (aType == "title" || aType == "url") - branch += "match."; - else - branch += "restrict."; - - if (prefs.prefHasUserValue(branch + aType)) - prefs.clearUserPref(branch + aType); -} diff --git a/toolkit/components/places/tests/autocomplete/test_swap_protocol.js b/toolkit/components/places/tests/autocomplete/test_swap_protocol.js deleted file mode 100644 index 860b722498e6..000000000000 --- a/toolkit/components/places/tests/autocomplete/test_swap_protocol.js +++ /dev/null @@ -1,63 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * Test bug 424717 to make sure searching with an existing location like - * http://site/ also matches https://site/ or ftp://site/. Same thing for - * ftp://site/ and https://site/. - * - * Test bug 461483 to make sure a search for "w" doesn't match the "www." from - * site subdomains. - */ - -// Define some shared uris and titles (each page needs its own uri) -var kURIs = [ - "http://www.site/", - "http://site/", - "ftp://ftp.site/", - "ftp://site/", - "https://www.site/", - "https://site/", - "http://woohoo/", - "http://wwwwwwacko/", -]; -var kTitles = [ - "title", -]; - -// Add various protocols of site -addPageBook(0, 0); -addPageBook(1, 0); -addPageBook(2, 0); -addPageBook(3, 0); -addPageBook(4, 0); -addPageBook(5, 0); -addPageBook(6, 0); -addPageBook(7, 0); - -var allSite = [0, 1, 2, 3, 4, 5]; - -// Provide for each test: description; search terms; array of gPages indices of -// pages that should match; optional function to be run before the test -var gTests = [ - ["0: http://www.site matches all site", "http://www.site", allSite], - ["1: http://site matches all site", "http://site", allSite], - ["2: ftp://ftp.site matches itself", "ftp://ftp.site", [2]], - ["3: ftp://site matches all site", "ftp://site", allSite], - ["4: https://www.site matches all site", "https://www.site", allSite], - ["5: https://site matches all site", "https://site", allSite], - ["6: www.site matches all site", "www.site", allSite], - - ["7: w matches none of www.", "w", [6, 7]], - ["8: http://w matches none of www.", "w", [6, 7]], - ["9: http://www.w matches none of www.", "w", [6, 7]], - - ["10: ww matches none of www.", "ww", [7]], - ["11: http://ww matches none of www.", "http://ww", [7]], - ["12: http://www.ww matches none of www.", "http://www.ww", [7]], - - ["13: www matches none of www.", "www", [7]], - ["14: http://www matches none of www.", "http://www", [7]], - ["15: http://www.www matches none of www.", "http://www.www", [7]], -]; diff --git a/toolkit/components/places/tests/autocomplete/test_tabmatches.js b/toolkit/components/places/tests/autocomplete/test_tabmatches.js deleted file mode 100644 index 98ada6c42e44..000000000000 --- a/toolkit/components/places/tests/autocomplete/test_tabmatches.js +++ /dev/null @@ -1,97 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- - * vim:set ts=2 sw=2 sts=2 et: - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -var gTabRestrictChar = "%"; -prefs.setCharPref("browser.urlbar.restrict.openpage", gTabRestrictChar); -do_register_cleanup(() => { - prefs.clearUserPref("browser.urlbar.restrict.openpage"); -}); - -var kSearchParam = "enable-actions"; - -var kURIs = [ - "http://abc.com/", - "moz-action:switchtab,http://abc.com/", - "http://xyz.net/", - "moz-action:switchtab,http://xyz.net/", - "about:mozilla", - "moz-action:switchtab,about:mozilla", - "data:text/html,test", - "moz-action:switchtab,data:text/html,test" -]; - -var kTitles = [ - "ABC rocks", - "xyz.net - we're better than ABC", - "about:mozilla", - "data:text/html,test" -]; - -addPageBook(0, 0); -gPages[1] = [1, 0]; -addPageBook(2, 1); -gPages[3] = [3, 1]; - -addOpenPages(0, 1); - -// PAges that cannot be registered in history. -addOpenPages(4, 1); -gPages[5] = [5, 2]; -addOpenPages(6, 1); -gPages[7] = [7, 3]; - -var gTests = [ - ["0: single result, that is also a tab match", - "abc.com", [1]], - ["1: two results, one tab match", - "abc", [1, 2]], - ["2: two results, both tab matches", - "abc", [1, 3], - function() { - addOpenPages(2, 1); - }], - ["3: two results, both tab matches, one has multiple tabs", - "abc", [1, 3], - function() { - addOpenPages(2, 5); - }], - ["4: two results, no tab matches", - "abc", [0, 2], - function() { - removeOpenPages(0, 1); - removeOpenPages(2, 6); - }], - ["5: tab match search with restriction character", - gTabRestrictChar + " abc", [1], - function() { - addOpenPages(0, 1); - }], - ["6: tab match with not-addable pages", - "mozilla", [5]], - ["7: tab match with not-addable pages and restriction character", - gTabRestrictChar + " mozilla", [5]], - ["8: tab match with not-addable pages and only restriction character", - gTabRestrictChar, [1, 5, 7]], -]; - - -function addOpenPages(aUri, aCount) { - let num = aCount || 1; - let acprovider = Cc["@mozilla.org/autocomplete/search;1?name=history"]. - getService(Ci.mozIPlacesAutoComplete); - for (let i = 0; i < num; i++) { - acprovider.registerOpenPage(toURI(kURIs[aUri])); - } -} - -function removeOpenPages(aUri, aCount) { - let num = aCount || 1; - let acprovider = Cc["@mozilla.org/autocomplete/search;1?name=history"]. - getService(Ci.mozIPlacesAutoComplete); - for (let i = 0; i < num; i++) { - acprovider.unregisterOpenPage(toURI(kURIs[aUri])); - } -} diff --git a/toolkit/components/places/tests/autocomplete/test_word_boundary_search.js b/toolkit/components/places/tests/autocomplete/test_word_boundary_search.js deleted file mode 100644 index b4ae3684911e..000000000000 --- a/toolkit/components/places/tests/autocomplete/test_word_boundary_search.js +++ /dev/null @@ -1,105 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * Test bug 393678 to make sure matches against the url, title, tags are only - * made on word boundaries instead of in the middle of words. - * - * Make sure we don't try matching one after a CamelCase because the upper-case - * isn't really a word boundary. (bug 429498) - * - * Bug 429531 provides switching between "must match on word boundary" and "can - * match," so leverage "must match" pref for checking word boundary logic and - * make sure "can match" matches anywhere. - */ - -var katakana = ["\u30a8", "\u30c9"]; // E, Do -var ideograph = ["\u4efb", "\u5929", "\u5802"]; // Nin Ten Do - -// Define some shared uris and titles (each page needs its own uri) -var kURIs = [ - "http://matchme/", - "http://dontmatchme/", - "http://title/1", - "http://title/2", - "http://tag/1", - "http://tag/2", - "http://crazytitle/", - "http://katakana/", - "http://ideograph/", - "http://camel/pleaseMatchMe/", -]; -var kTitles = [ - "title1", - "matchme2", - "dontmatchme3", - "!@#$%^&*()_+{}|:<>?word", - katakana.join(""), - ideograph.join(""), -]; - -// Boundaries on the url -addPageBook(0, 0); -addPageBook(1, 0); -// Boundaries on the title -addPageBook(2, 1); -addPageBook(3, 2); -// Boundaries on the tag -addPageBook(4, 0, 0, [1]); -addPageBook(5, 0, 0, [2]); -// Lots of word boundaries before a word -addPageBook(6, 3); -// Katakana -addPageBook(7, 4); -// Ideograph -addPageBook(8, 5); -// CamelCase -addPageBook(9, 0); - -// Provide for each test: description; search terms; array of gPages indices of -// pages that should match; optional function to be run before the test -var gTests = [ - // Tests after this one will match only on word boundaries - ["0: Match 'match' at the beginning or after / or on a CamelCase", - "match", [0, 2, 4, 9], - () => setBehavior(2)], - ["1: Match 'dont' at the beginning or after /", - "dont", [1, 3, 5]], - ["2: Match '2' after the slash and after a word (in tags too)", - "2", [2, 3, 4, 5]], - ["3: Match 't' at the beginning or after /", - "t", [0, 1, 2, 3, 4, 5, 9]], - ["4: Match 'word' after many consecutive word boundaries", - "word", [6]], - ["5: Match a word boundary '/' for everything", - "/", [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]], - ["6: Match word boundaries '()_+' that are among word boundaries", - "()_+", [6]], - - ["7: Katakana characters form a string, so match the beginning", - katakana[0], [7]], - /*["8: Middle of a katakana word shouldn't be matched", - katakana[1], []],*/ - - ["9: Ideographs are treated as words so 'nin' is one word", - ideograph[0], [8]], - ["10: Ideographs are treated as words so 'ten' is another word", - ideograph[1], [8]], - ["11: Ideographs are treated as words so 'do' is yet another", - ideograph[2], [8]], - - ["12: Extra negative assert that we don't match in the middle", - "ch", []], - ["13: Don't match one character after a camel-case word boundary (bug 429498)", - "atch", []], - - // Tests after this one will match against word boundaries and anywhere - ["14: Match on word boundaries as well as anywhere (bug 429531)", - "tch", [0, 1, 2, 3, 4, 5, 9], - () => setBehavior(1)], -]; - -function setBehavior(aType) { - prefs.setIntPref("browser.urlbar.matchBehavior", aType); -} diff --git a/toolkit/components/places/tests/autocomplete/xpcshell.ini b/toolkit/components/places/tests/autocomplete/xpcshell.ini deleted file mode 100644 index 7c018dbcc7b7..000000000000 --- a/toolkit/components/places/tests/autocomplete/xpcshell.ini +++ /dev/null @@ -1,29 +0,0 @@ -[DEFAULT] -head = head_autocomplete.js -tail = -skip-if = toolkit == 'android' || toolkit == 'gonk' - -[test_416211.js] -[test_416214.js] -[test_417798.js] -[test_418257.js] -[test_422277.js] -[test_autocomplete_on_value_removed_479089.js] -# Bug 676989: test fails consistently on Android -fail-if = os == "android" -[test_download_embed_bookmarks.js] -# Bug 676989: test fails consistently on Android -fail-if = os == "android" -[test_empty_search.js] -# Bug 676989: test fails consistently on Android -fail-if = os == "android" -[test_enabled.js] -[test_escape_self.js] -[test_ignore_protocol.js] -[test_keyword_search.js] -[test_match_beginning.js] -[test_multi_word_search.js] -[test_special_search.js] -[test_swap_protocol.js] -[test_tabmatches.js] -[test_word_boundary_search.js] diff --git a/toolkit/components/places/tests/moz.build b/toolkit/components/places/tests/moz.build index d3a2c79fc260..5f9460babfd9 100644 --- a/toolkit/components/places/tests/moz.build +++ b/toolkit/components/places/tests/moz.build @@ -22,11 +22,6 @@ XPCSHELL_TESTS_MANIFESTS += [ 'unit/xpcshell.ini', ] -if CONFIG['MOZ_SUITE']: - XPCSHELL_TESTS_MANIFESTS += [ - 'autocomplete/xpcshell.ini', - ] - BROWSER_CHROME_MANIFESTS += ['browser/browser.ini'] MOCHITEST_CHROME_MANIFESTS += [ 'chrome/chrome.ini', From 419860c96f44a887274e7f8a6433540102720509 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Mon, 26 Sep 2016 11:09:42 +0200 Subject: [PATCH 019/102] Bug 1292723: Add wasm/validate.js tests; r=luke MozReview-Commit-ID: K78QF3FKw1p --HG-- extra : rebase_source : 836af3264df5880069c7d844b4bc506f2baf8ba5 extra : amend_source : 03e5538ae87450127dbc204f08e431781eed7fd1 --- js/src/jit-test/tests/wasm/validate.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 js/src/jit-test/tests/wasm/validate.js diff --git a/js/src/jit-test/tests/wasm/validate.js b/js/src/jit-test/tests/wasm/validate.js new file mode 100644 index 000000000000..d56f01d98c14 --- /dev/null +++ b/js/src/jit-test/tests/wasm/validate.js @@ -0,0 +1,26 @@ +// |jit-test| test-also-wasm-baseline +load(libdir + "wasm.js"); + +const { validate } = WebAssembly; + +assertErrorMessage(() => validate(), Error, /requires more than 0 arguments/); + +const argError = /first argument must be an ArrayBuffer or typed array object/; +assertErrorMessage(() => validate(null), Error, argError); +assertErrorMessage(() => validate(true), Error, argError); +assertErrorMessage(() => validate(42), Error, argError); +assertErrorMessage(() => validate(NaN), Error, argError); +assertErrorMessage(() => validate('yo'), Error, argError); +assertErrorMessage(() => validate([]), Error, argError); +assertErrorMessage(() => validate({}), Error, argError); +assertErrorMessage(() => validate(Symbol.iterator), Error, argError); +assertErrorMessage(() => validate({ valueOf: () => new ArrayBuffer(65536) }), Error, argError); + +assertEq(validate(wasmTextToBinary(`(module)`)), true); + +assertEq(validate(wasmTextToBinary(`(module (export "run" 0))`)), false); +assertEq(validate(wasmTextToBinary(`(module (func) (export "run" 0))`)), true); + +// Feature-testing proof-of-concept. +assertEq(validate(wasmTextToBinary(`(module (memory 1) (func (result i32) (current_memory)))`)), true); +assertEq(validate(wasmTextToBinary(`(module (memory 1) (func (result i32) (grow_memory (i32.const 42))))`)), true); From 36f06cc08f96a1b9092042325742a62aac334146 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Mon, 26 Sep 2016 11:04:04 +0200 Subject: [PATCH 020/102] Bug 1305197: Return value of WebAssembly_validate must be consistent with werror; r=luke MozReview-Commit-ID: 3WqMltmc35l --HG-- extra : rebase_source : e8518af45727140067e599c48371e180c65dab35 extra : amend_source : 0b513f243b5e8bd74bf3f82f3f837ef4c54f1d99 --- js/src/asmjs/WasmJS.cpp | 6 +++--- js/src/jit-test/tests/wasm/validate.js | 7 +++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/js/src/asmjs/WasmJS.cpp b/js/src/asmjs/WasmJS.cpp index f5846ab7606c..6249ae48992c 100644 --- a/js/src/asmjs/WasmJS.cpp +++ b/js/src/asmjs/WasmJS.cpp @@ -1578,9 +1578,9 @@ WebAssembly_validate(JSContext* cx, unsigned argc, Value* vp) return false; } - if (error) { - JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, GetErrorMessage, nullptr, - JSMSG_WASM_COMPILE_ERROR, error.get()); + if (error && !JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, GetErrorMessage, nullptr, + JSMSG_WASM_COMPILE_ERROR, error.get())) { + return false; } callArgs.rval().setBoolean(validated); diff --git a/js/src/jit-test/tests/wasm/validate.js b/js/src/jit-test/tests/wasm/validate.js index d56f01d98c14..81891e83e2c7 100644 --- a/js/src/jit-test/tests/wasm/validate.js +++ b/js/src/jit-test/tests/wasm/validate.js @@ -24,3 +24,10 @@ assertEq(validate(wasmTextToBinary(`(module (func) (export "run" 0))`)), true); // Feature-testing proof-of-concept. assertEq(validate(wasmTextToBinary(`(module (memory 1) (func (result i32) (current_memory)))`)), true); assertEq(validate(wasmTextToBinary(`(module (memory 1) (func (result i32) (grow_memory (i32.const 42))))`)), true); + +// Enable warning as errors. +options("werror"); +assertErrorMessage(() => validate(wasmTextToBinary(`(module (func) (func) (export "a" 2))`)), + WebAssembly.CompileError, + /exported function index out of bounds/); +options("werror"); From 08bcfd5279e0f5e41d8e387bd3b80cdbeb6350b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A3o=20Gottwald?= Date: Tue, 27 Sep 2016 11:57:38 +0200 Subject: [PATCH 021/102] Bug 1304363 - Use preprocessing instead of CSS variables for identity block icon variants. r=gijs --- browser/themes/shared/devedition.inc.css | 21 ++--- .../shared/identity-block/icons.inc.css | 62 +++++++++++++ .../identity-block/identity-block.inc.css | 88 +++---------------- 3 files changed, 79 insertions(+), 92 deletions(-) create mode 100644 browser/themes/shared/identity-block/icons.inc.css diff --git a/browser/themes/shared/devedition.inc.css b/browser/themes/shared/devedition.inc.css index d667d021f9ff..900fcf50d7cc 100644 --- a/browser/themes/shared/devedition.inc.css +++ b/browser/themes/shared/devedition.inc.css @@ -191,22 +191,11 @@ toolbar[brighttext] #downloads-indicator-counter { box-shadow: none !important; } -:root[devtoolstheme="dark"] #identity-icon:-moz-lwtheme { - --identity-icon-normal: url(chrome://browser/skin/identity-icon.svg#normal-white); - --identity-icon-hover: url(chrome://browser/skin/identity-icon.svg#hover-white); - --identity-icon-notice: url(chrome://browser/skin/identity-icon.svg#notice-white); - --identity-icon-notice-hover: url(chrome://browser/skin/identity-icon.svg#notice-hover-white); -} - -:root[devtoolstheme="dark"] #tracking-protection-icon:-moz-lwtheme { - --tracking-protection-icon-enabled: url(chrome://browser/skin/tracking-protection-16.svg#enabled-white); - --tracking-protection-icon-disabled: url(chrome://browser/skin/tracking-protection-16.svg#disabled-white); -} - -:root[devtoolstheme="dark"] #connection-icon:-moz-lwtheme { - --connection-icon-mixed-passive-loaded: url(chrome://browser/skin/connection-mixed-passive-loaded.svg#icon-white); - --connection-icon-mixed-active-loaded: url(chrome://browser/skin/connection-mixed-active-loaded.svg#icon-white); -} +%filter substitution +%define selectorPrefix :root[devtoolstheme="dark"] +%define selectorSuffix :-moz-lwtheme +%define iconVariant -white +%include identity-block/icons.inc.css #urlbar { border-inline-start: none !important; diff --git a/browser/themes/shared/identity-block/icons.inc.css b/browser/themes/shared/identity-block/icons.inc.css new file mode 100644 index 000000000000..9146683abf5f --- /dev/null +++ b/browser/themes/shared/identity-block/icons.inc.css @@ -0,0 +1,62 @@ +%if 0 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +%endif + +@selectorPrefix@#identity-icon@selectorSuffix@ { + list-style-image: url(chrome://browser/skin/identity-icon.svg#normal@iconVariant@); +} + +@selectorPrefix@#identity-box:hover > #identity-icon:not(.no-hover)@selectorSuffix@, +@selectorPrefix@#identity-box[open=true] > #identity-icon@selectorSuffix@ { + list-style-image: url(chrome://browser/skin/identity-icon.svg#hover@iconVariant@); +} + +@selectorPrefix@#identity-box.grantedPermissions > #identity-icon@selectorSuffix@ { + list-style-image: url(chrome://browser/skin/identity-icon.svg#notice@iconVariant@); +} + +@selectorPrefix@#identity-box.grantedPermissions:hover > #identity-icon:not(.no-hover)@selectorSuffix@, +@selectorPrefix@#identity-box.grantedPermissions[open=true] > #identity-icon@selectorSuffix@ { + list-style-image: url(url(chrome://browser/skin/identity-icon.svg#notice-hover@iconVariant@)); +} + +@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.chromeUI > #identity-icon@selectorSuffix@ { + list-style-image: url(chrome://branding/content/identity-icons-brand.svg); +} + + +@selectorPrefix@#tracking-protection-icon@selectorSuffix@ { + list-style-image: url(chrome://browser/skin/tracking-protection-16.svg#enabled@iconVariant@); +} + +@selectorPrefix@#tracking-protection-icon[state="loaded-tracking-content"]@selectorSuffix@ { + list-style-image: url(chrome://browser/skin/tracking-protection-16.svg#disabled@iconVariant@); +} + + +@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.verifiedDomain > #connection-icon@selectorSuffix@, +@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity > #connection-icon@selectorSuffix@, +@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.mixedActiveBlocked > #connection-icon@selectorSuffix@ { + list-style-image: url(chrome://browser/skin/connection-secure.svg); + visibility: visible; +} + +@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.certUserOverridden > #connection-icon@selectorSuffix@ { + list-style-image: url(chrome://browser/skin/connection-mixed-passive-loaded.svg#icon@iconVariant@); + visibility: visible; +} + +@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.insecureLoginForms > #connection-icon@selectorSuffix@, +@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.mixedActiveContent > #connection-icon@selectorSuffix@ { + list-style-image: url(chrome://browser/skin/connection-mixed-active-loaded.svg#icon@iconVariant@); + visibility: visible; +} + +@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.weakCipher > #connection-icon@selectorSuffix@, +@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.mixedDisplayContent > #connection-icon@selectorSuffix@, +@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.mixedDisplayContentLoadedActiveBlocked > #connection-icon@selectorSuffix@ { + list-style-image: url(chrome://browser/skin/connection-mixed-passive-loaded.svg#icon@iconVariant@); + visibility: visible; +} diff --git a/browser/themes/shared/identity-block/identity-block.inc.css b/browser/themes/shared/identity-block/identity-block.inc.css index 01922edb52b0..d8627806649c 100644 --- a/browser/themes/shared/identity-block/identity-block.inc.css +++ b/browser/themes/shared/identity-block/identity-block.inc.css @@ -4,6 +4,18 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ %endif +%filter substitution + +%define selectorPrefix +%define selectorSuffix +%define iconVariant +%include icons.inc.css + +%define selectorPrefix +%define selectorSuffix :-moz-lwtheme +%define iconVariant -black +%include icons.inc.css + #identity-box { font-size: .9em; padding: 3px 5px; @@ -52,39 +64,8 @@ /* MAIN IDENTITY ICON */ #identity-icon { - --identity-icon-normal: url(chrome://browser/skin/identity-icon.svg#normal); - --identity-icon-hover: url(chrome://browser/skin/identity-icon.svg#hover); - --identity-icon-notice: url(chrome://browser/skin/identity-icon.svg#notice); - --identity-icon-notice-hover: url(chrome://browser/skin/identity-icon.svg#notice-hover); - width: 16px; height: 16px; - list-style-image: var(--identity-icon-normal); -} - -#identity-icon:-moz-lwtheme { - --identity-icon-normal: url(chrome://browser/skin/identity-icon.svg#normal-black); - --identity-icon-hover: url(chrome://browser/skin/identity-icon.svg#hover-black); - --identity-icon-notice: url(chrome://browser/skin/identity-icon.svg#notice-black); - --identity-icon-notice-hover: url(chrome://browser/skin/identity-icon.svg#notice-hover-black); -} - -#identity-box:hover > #identity-icon:not(.no-hover), -#identity-box[open=true] > #identity-icon { - list-style-image: var(--identity-icon-hover); -} - -#identity-box.grantedPermissions > #identity-icon { - list-style-image: var(--identity-icon-notice); -} - -#identity-box.grantedPermissions:hover > #identity-icon:not(.no-hover), -#identity-box.grantedPermissions[open=true] > #identity-icon { - list-style-image: var(--identity-icon-notice-hover); -} - -#urlbar[pageproxystate="valid"] > #identity-box.chromeUI > #identity-icon { - list-style-image: url(chrome://branding/content/identity-icons-brand.svg); } #urlbar[pageproxystate="invalid"] > #identity-box > #identity-icon { @@ -142,23 +123,10 @@ /* TRACKING PROTECTION ICON */ #tracking-protection-icon { - --tracking-protection-icon-enabled: url(chrome://browser/skin/tracking-protection-16.svg#enabled); - --tracking-protection-icon-disabled: url(chrome://browser/skin/tracking-protection-16.svg#disabled); - width: 16px; height: 16px; margin-inline-start: 2px; margin-inline-end: 0; - list-style-image: var(--tracking-protection-icon-enabled); -} - -#tracking-protection-icon:-moz-lwtheme { - --tracking-protection-icon-enabled: url(chrome://browser/skin/tracking-protection-16.svg#enabled-black); - --tracking-protection-icon-disabled: url(chrome://browser/skin/tracking-protection-16.svg#disabled-black); -} - -#tracking-protection-icon[state="loaded-tracking-content"] { - list-style-image: var(--tracking-protection-icon-disabled); } #tracking-protection-icon[animate] { @@ -184,37 +152,5 @@ height: 16px; margin-inline-start: 2px; visibility: collapse; - - --connection-icon-mixed-passive-loaded: url(chrome://browser/skin/connection-mixed-passive-loaded.svg#icon); - --connection-icon-mixed-active-loaded: url(chrome://browser/skin/connection-mixed-active-loaded.svg#icon); } -#connection-icon:-moz-lwtheme { - --connection-icon-mixed-passive-loaded: url(chrome://browser/skin/connection-mixed-passive-loaded.svg#icon-black); - --connection-icon-mixed-active-loaded: url(chrome://browser/skin/connection-mixed-active-loaded.svg#icon-black); -} - -#urlbar[pageproxystate="valid"] > #identity-box.verifiedDomain > #connection-icon, -#urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity > #connection-icon, -#urlbar[pageproxystate="valid"] > #identity-box.mixedActiveBlocked > #connection-icon { - list-style-image: url(chrome://browser/skin/connection-secure.svg); - visibility: visible; -} - -#urlbar[pageproxystate="valid"] > #identity-box.certUserOverridden > #connection-icon { - list-style-image: var(--connection-icon-mixed-passive-loaded); - visibility: visible; -} - -#urlbar[pageproxystate="valid"] > #identity-box.insecureLoginForms > #connection-icon, -#urlbar[pageproxystate="valid"] > #identity-box.mixedActiveContent > #connection-icon { - list-style-image: var(--connection-icon-mixed-active-loaded); - visibility: visible; -} - -#urlbar[pageproxystate="valid"] > #identity-box.weakCipher > #connection-icon, -#urlbar[pageproxystate="valid"] > #identity-box.mixedDisplayContent > #connection-icon, -#urlbar[pageproxystate="valid"] > #identity-box.mixedDisplayContentLoadedActiveBlocked > #connection-icon { - list-style-image: var(--connection-icon-mixed-passive-loaded); - visibility: visible; -} From a0109e9d9f0e125058ef672399629dda89f7ea08 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Tue, 27 Sep 2016 09:59:09 +0000 Subject: [PATCH 022/102] Bug 1298354 - Do not add AssertRange instructions in unreachable blocks. r=sunfish --- js/src/jit-test/tests/ion/bug1298354.js | 17 +++++++++++++++++ js/src/jit/RangeAnalysis.cpp | 4 ++++ 2 files changed, 21 insertions(+) create mode 100644 js/src/jit-test/tests/ion/bug1298354.js diff --git a/js/src/jit-test/tests/ion/bug1298354.js b/js/src/jit-test/tests/ion/bug1298354.js new file mode 100644 index 000000000000..73502df5a791 --- /dev/null +++ b/js/src/jit-test/tests/ion/bug1298354.js @@ -0,0 +1,17 @@ +// |jit-test| error: ReferenceError + +new Function(` + while (true) { + try { + var buf = new Uint8ClampedArray(a); + } catch (e) { + break; + } + } + var caughtInvalidArguments = false; + while (true) { + var a = inIon() ? -true.get : 0; + while (x > 7 & 0) {} + } +`)(); + diff --git a/js/src/jit/RangeAnalysis.cpp b/js/src/jit/RangeAnalysis.cpp index d7ad1bd3b2ec..09da6f99cee3 100644 --- a/js/src/jit/RangeAnalysis.cpp +++ b/js/src/jit/RangeAnalysis.cpp @@ -2346,6 +2346,10 @@ RangeAnalysis::addRangeAssertions() for (ReversePostorderIterator iter(graph_.rpoBegin()); iter != graph_.rpoEnd(); iter++) { MBasicBlock* block = *iter; + // Do not add assertions in unreachable blocks. + if (block->unreachable()) + continue; + for (MDefinitionIterator iter(block); iter; iter++) { MDefinition* ins = *iter; From 653a0511a56af10028c3ba90f6187e00eed44356 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Tue, 27 Sep 2016 10:07:59 +0000 Subject: [PATCH 023/102] Bug 1299007 - Ensure enough ballast space in RangeAnalysis::prepareForUCE. r=sunfish --- js/src/jit-test/tests/ion/bug1299007.js | 41 +++++++++++++++++++++++++ js/src/jit/RangeAnalysis.cpp | 15 ++++----- 2 files changed, 49 insertions(+), 7 deletions(-) create mode 100644 js/src/jit-test/tests/ion/bug1299007.js diff --git a/js/src/jit-test/tests/ion/bug1299007.js b/js/src/jit-test/tests/ion/bug1299007.js new file mode 100644 index 000000000000..fb7f15184d5c --- /dev/null +++ b/js/src/jit-test/tests/ion/bug1299007.js @@ -0,0 +1,41 @@ + +evalInFrame = function(global) { + dbgGlobal = newGlobal() + dbg = new dbgGlobal.Debugger + return function(upCount, code) { + dbg.addDebuggee(global) + var frame = dbg.getNewestFrame().older + for (var i = 0; i < upCount; i++) + if (!frame) frame = older + completion = frame.eval(code) + } +}(this); +function h() { + evalInFrame(0, "") + evalInFrame(0, "i") + evalInFrame(0, "a.push") + evalInFrame(1, "a.pushy") +} +function g() h() +function f() g() +f() +evaluate(` +g() +g() +g() +g() +g() +g() +g() +g() +g() +g() +g() +g() +g() +g() +g() +g() +g() +h() +`); diff --git a/js/src/jit/RangeAnalysis.cpp b/js/src/jit/RangeAnalysis.cpp index 09da6f99cee3..3921e0b9d948 100644 --- a/js/src/jit/RangeAnalysis.cpp +++ b/js/src/jit/RangeAnalysis.cpp @@ -3495,13 +3495,14 @@ RangeAnalysis::prepareForUCE(bool* shouldRemoveDeadCode) // added by MBeta::computeRange on its own block. MTest* test = cond->toTest(); MDefinition* condition = test->input(); - MConstant* constant = nullptr; - if (block == test->ifTrue()) { - constant = MConstant::New(alloc(), BooleanValue(false)); - } else { - MOZ_ASSERT(block == test->ifFalse()); - constant = MConstant::New(alloc(), BooleanValue(true)); - } + + // If the false-branch is unreachable, then the test condition must be true. + // If the true-branch is unreachable, then the test condition must be false. + MOZ_ASSERT(block == test->ifTrue() || block == test->ifFalse()); + bool value = block == test->ifFalse(); + MConstant* constant = MConstant::New(alloc().fallible(), BooleanValue(value)); + if (!constant) + return false; if (DeadIfUnused(condition)) condition->setGuardRangeBailoutsUnchecked(); From 0753e4f3223934bddce62031d1c483668906c610 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Tue, 27 Sep 2016 10:07:59 +0000 Subject: [PATCH 024/102] Bug 1296667 - Ensure enough ballast space when given large list of parameters. r=h4writer --- js/src/jit-test/tests/ion/bug1296667.js | 11 +++++++++++ js/src/jit/IonBuilder.cpp | 24 +++++++++++++++++------- js/src/jit/IonBuilder.h | 4 ++-- js/src/jit/MIR.cpp | 9 ++++----- js/src/jit/MIR.h | 6 ++---- 5 files changed, 36 insertions(+), 18 deletions(-) create mode 100644 js/src/jit-test/tests/ion/bug1296667.js diff --git a/js/src/jit-test/tests/ion/bug1296667.js b/js/src/jit-test/tests/ion/bug1296667.js new file mode 100644 index 000000000000..24cf5ff80489 --- /dev/null +++ b/js/src/jit-test/tests/ion/bug1296667.js @@ -0,0 +1,11 @@ +args = "" +for (i = 0; i < 2000; i++) { + args += "arg" + i; + if (i != 1999) args += ","; +} +MyFunc = MyObject = Function(args, "for (var i = 0; i < MyFunc.length; i++ ) break; eval('this.arg'+i +'=arg'+i) "); +new function TestCase() { + if (inIon()) + return; + TestCase(eval("var EXP_1 = new MyObject; var EXP_2 = new MyObject; EXP_1 - EXP_2")); +} diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index a4aa7405a7e6..acb304c9e4c0 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -823,7 +823,8 @@ IonBuilder::build() } #endif - initParameters(); + if (!initParameters()) + return false; initLocals(); // Initialize something for the env chain. We can bail out before the @@ -862,7 +863,8 @@ IonBuilder::build() // Parameters have been checked to correspond to the typeset, now we unbox // what we can in an infallible manner. - rewriteParameters(); + if (!rewriteParameters()) + return false; // Check for redeclaration errors for global scripts. if (!info().funMaybeLazy() && !info().module() && @@ -1136,25 +1138,29 @@ IonBuilder::rewriteParameter(uint32_t slotIdx, MDefinition* param, int32_t argIn // Apply Type Inference information to parameters early on, unboxing them if // they have a definitive type. The actual guards will be emitted by the code // generator, explicitly, as part of the function prologue. -void +bool IonBuilder::rewriteParameters() { MOZ_ASSERT(info().environmentChainSlot() == 0); if (!info().funMaybeLazy()) - return; + return true; for (uint32_t i = info().startArgSlot(); i < info().endArgSlot(); i++) { + if (!alloc().ensureBallast()) + return false; MDefinition* param = current->getSlot(i); rewriteParameter(i, param, param->toParameter()->index()); } + + return true; } -void +bool IonBuilder::initParameters() { if (!info().funMaybeLazy()) - return; + return true; // If we are doing OSR on a frame which initially executed in the // interpreter and didn't accumulate type information, try to use that OSR @@ -1182,10 +1188,14 @@ IonBuilder::initParameters() types->addType(type, alloc_->lifoAlloc()); } - param = MParameter::New(alloc(), i, types); + param = MParameter::New(alloc().fallible(), i, types); + if (!param) + return false; current->add(param); current->initSlot(info().argSlotUnchecked(i), param); } + + return true; } void diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index 170488a148f2..dad2fb8e73d1 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -336,10 +336,10 @@ class IonBuilder void insertRecompileCheck(); - void initParameters(); + MOZ_MUST_USE bool initParameters(); void initLocals(); void rewriteParameter(uint32_t slotIdx, MDefinition* param, int32_t argIndex); - void rewriteParameters(); + MOZ_MUST_USE bool rewriteParameters(); MOZ_MUST_USE bool initEnvironmentChain(MDefinition* callee = nullptr); MOZ_MUST_USE bool initArgumentsObject(); void pushConstant(const Value& v); diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 8c9f0ca39e8e..5bf69c88caf0 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -1867,11 +1867,10 @@ MAtomicIsLockFree::foldsTo(TempAllocator& alloc) return MConstant::New(alloc, BooleanValue(AtomicOperations::isLockfree(i))); } -MParameter* -MParameter::New(TempAllocator& alloc, int32_t index, TemporaryTypeSet* types) -{ - return new(alloc) MParameter(index, types); -} +// Define |THIS_SLOT| as part of this translation unit, as it is used to +// specialized the parameterized |New| function calls introduced by +// TRIVIAL_NEW_WRAPPERS. +const int32_t MParameter::THIS_SLOT; void MParameter::printOpcode(GenericPrinter& out) const diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index d99f3125cc02..18ad32586d59 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -2665,9 +2665,6 @@ class MParameter : public MNullaryInstruction { int32_t index_; - public: - static const int32_t THIS_SLOT = -1; - MParameter(int32_t index, TemporaryTypeSet* types) : index_(index) { @@ -2677,8 +2674,9 @@ class MParameter : public MNullaryInstruction public: INSTRUCTION_HEADER(Parameter) - static MParameter* New(TempAllocator& alloc, int32_t index, TemporaryTypeSet* types); + TRIVIAL_NEW_WRAPPERS + static const int32_t THIS_SLOT = -1; int32_t index() const { return index_; } From add5fa9ec4d68f868f57f7bef61dfc0637466af5 Mon Sep 17 00:00:00 2001 From: Henri Sivonen Date: Tue, 27 Sep 2016 13:47:53 +0300 Subject: [PATCH 025/102] Bug 1286911. r=wchen. MozReview-Commit-ID: hzAu0jKAxt --- parser/html/javasrc/HtmlAttributes.java | 2 +- parser/html/javasrc/Tokenizer.java | 183 ++++++++++++------ parser/html/nsHtml5Tokenizer.cpp | 140 ++++++++------ parser/html/nsHtml5Tokenizer.h | 41 ++-- parser/html/nsHtml5TreeBuilderCppSupplement.h | 4 +- 5 files changed, 239 insertions(+), 131 deletions(-) diff --git a/parser/html/javasrc/HtmlAttributes.java b/parser/html/javasrc/HtmlAttributes.java index 029703c19fa7..0ec25f96f0ae 100644 --- a/parser/html/javasrc/HtmlAttributes.java +++ b/parser/html/javasrc/HtmlAttributes.java @@ -62,7 +62,7 @@ public final class HtmlAttributes implements Attributes { private @Auto AttributeName[] names; private @Auto String[] values; // XXX perhaps make this @NoLength? - + // CPPONLY: private @Auto int[] lines; // XXX perhaps make this @NoLength? // [NOCPP[ diff --git a/parser/html/javasrc/Tokenizer.java b/parser/html/javasrc/Tokenizer.java index 14ad0c0722ab..7e529035d846 100644 --- a/parser/html/javasrc/Tokenizer.java +++ b/parser/html/javasrc/Tokenizer.java @@ -817,30 +817,34 @@ public class Tokenizer implements Locator { } @Inline private void appendCharRefBuf(char c) { + // CPPONLY: assert charRefBufLen < charRefBuf.length: + // CPPONLY: "RELEASE: Attempted to overrun charRefBuf!"; charRefBuf[charRefBufLen++] = c; } - @Inline private void clearCharRefBufAndAppend(char c) { - charRefBuf[0] = c; - charRefBufLen = 1; - } - private void emitOrAppendCharRefBuf(int returnState) throws SAXException { if ((returnState & DATA_AND_RCDATA_MASK) != 0) { appendCharRefBufToStrBuf(); } else { if (charRefBufLen > 0) { tokenHandler.characters(charRefBuf, 0, charRefBufLen); + charRefBufLen = 0; } } } - @Inline private void clearStrBufAndAppend(char c) { - strBuf[0] = c; - strBufLen = 1; + @Inline private void clearStrBufAfterUse() { + strBufLen = 0; } - @Inline private void clearStrBuf() { + @Inline private void clearStrBufBeforeUse() { + assert strBufLen == 0: "strBufLen not reset after previous use!"; + strBufLen = 0; // no-op in the absence of bugs + } + + @Inline private void clearStrBufAfterOneHyphen() { + assert strBufLen == 1: "strBufLen length not one!"; + assert strBuf[0] == '-': "strBuf does not start with a hyphen!"; strBufLen = 0; } @@ -850,7 +854,13 @@ public class Tokenizer implements Locator { * @param c * the UTF-16 code unit to append */ - private void appendStrBuf(char c) { + @Inline private void appendStrBuf(char c) { + // CPPONLY: assert strBufLen < strBuf.length: "Previous buffer length insufficient."; + // CPPONLY: if (strBufLen == strBuf.length) { + // CPPONLY: if (!EnsureBufferSpace(1)) { + // CPPONLY: assert false: "RELEASE: Unable to recover from buffer reallocation failure"; + // CPPONLY: } // TODO: Add telemetry when outer if fires but inner does not + // CPPONLY: } strBuf[strBufLen++] = c; } @@ -863,9 +873,11 @@ public class Tokenizer implements Locator { * @return the buffer as a string */ protected String strBufToString() { - return Portability.newStringFromBuffer(strBuf, 0, strBufLen + String str = Portability.newStringFromBuffer(strBuf, 0, strBufLen // CPPONLY: , tokenHandler ); + clearStrBufAfterUse(); + return str; } /** @@ -877,6 +889,7 @@ public class Tokenizer implements Locator { private void strBufToDoctypeName() { doctypeName = Portability.newLocalNameFromBuffer(strBuf, 0, strBufLen, interner); + clearStrBufAfterUse(); } /** @@ -888,6 +901,7 @@ public class Tokenizer implements Locator { private void emitStrBuf() throws SAXException { if (strBufLen > 0) { tokenHandler.characters(strBuf, 0, strBufLen); + clearStrBufAfterUse(); } } @@ -934,6 +948,8 @@ public class Tokenizer implements Locator { switch (commentPolicy) { case ALTER_INFOSET: strBufLen--; + // WARNING!!! This expands the worst case of the buffer length + // given the length of input! appendStrBuf(' '); appendStrBuf('-'); // FALLTHROUGH @@ -951,14 +967,15 @@ public class Tokenizer implements Locator { } private void appendStrBuf(@NoLength char[] buffer, int offset, int length) { - int reqLen = strBufLen + length; - if (strBuf.length < reqLen) { - char[] newBuf = new char[reqLen + (reqLen >> 1)]; - System.arraycopy(strBuf, 0, newBuf, 0, strBuf.length); - strBuf = newBuf; - } + int newLen = strBufLen + length; + // CPPONLY: assert newLen <= strBuf.length: "Previous buffer length insufficient."; + // CPPONLY: if (strBuf.length < newLen) { + // CPPONLY: if (!EnsureBufferSpace(length)) { + // CPPONLY: assert false: "RELEASE: Unable to recover from buffer reallocation failure"; + // CPPONLY: } // TODO: Add telemetry when outer if fires but inner does not + // CPPONLY: } System.arraycopy(buffer, offset, strBuf, strBufLen, length); - strBufLen = reqLen; + strBufLen = newLen; } /** @@ -966,6 +983,7 @@ public class Tokenizer implements Locator { */ @Inline private void appendCharRefBufToStrBuf() { appendStrBuf(charRefBuf, 0, charRefBufLen); + charRefBufLen = 0; } /** @@ -986,6 +1004,7 @@ public class Tokenizer implements Locator { // [NOCPP[ } // ]NOCPP] + clearStrBufAfterUse(); cstart = pos + 1; } @@ -1073,6 +1092,7 @@ public class Tokenizer implements Locator { private void strBufToElementNameString() { tagName = ElementName.elementNameByBuffer(strBuf, 0, strBufLen, interner); + clearStrBufAfterUse(); } private int emitCurrentTagToken(boolean selfClosing, int pos) @@ -1124,6 +1144,7 @@ public class Tokenizer implements Locator { , namePolicy != XmlViolationPolicy.ALLOW // ]NOCPP] , interner); + clearStrBufAfterUse(); if (attributes == null) { attributes = new HtmlAttributes(mappingLangToXmlLang); @@ -1190,6 +1211,8 @@ public class Tokenizer implements Locator { // ]NOCPP] attributeName = null; // attributeName has been adopted by the // |attributes| object + } else { + clearStrBufAfterUse(); } } @@ -1338,6 +1361,14 @@ public class Tokenizer implements Locator { // unifying the tokenizer and tree builder buffers in the future. int worstCase = strBufLen + inputLength + charRefBufLen + 2; tokenHandler.ensureBufferSpace(worstCase); + if (commentPolicy == XmlViolationPolicy.ALTER_INFOSET) { + // When altering infoset, if the comment contents are consecutive + // hyphens, each hyphen generates a space, too. These buffer + // contents never get emitted as characters() to the tokenHandler, + // which is why this calculation happens after the call to + // ensureBufferSpace on tokenHandler. + worstCase *= 2; + } if (strBuf == null) { // Add an arbitrary small value to avoid immediate reallocation // once there are a few characters in the buffer. @@ -1446,7 +1477,8 @@ public class Tokenizer implements Locator { * reference in data state. */ flushChars(buf, pos); - clearCharRefBufAndAppend(c); + assert charRefBufLen == 0: "charRefBufLen not reset after previous use!"; + appendCharRefBuf(c); setAdditionalAndRememberAmpersandLocation('\u0000'); returnState = state; state = transition(state, Tokenizer.CONSUME_CHARACTER_REFERENCE, reconsume, pos); @@ -1506,7 +1538,8 @@ public class Tokenizer implements Locator { * input character (add 0x0020 to the character's * code point), */ - clearStrBufAndAppend((char) (c + 0x20)); + clearStrBufBeforeUse(); + appendStrBuf((char) (c + 0x20)); /* then switch to the tag name state. */ state = transition(state, Tokenizer.TAG_NAME, reconsume, pos); /* @@ -1525,7 +1558,8 @@ public class Tokenizer implements Locator { /* * set its tag name to the input character, */ - clearStrBufAndAppend(c); + clearStrBufBeforeUse(); + appendStrBuf(c); /* then switch to the tag name state. */ state = transition(state, Tokenizer.TAG_NAME, reconsume, pos); /* @@ -1565,7 +1599,8 @@ public class Tokenizer implements Locator { /* * Switch to the bogus comment state. */ - clearStrBufAndAppend(c); + clearStrBufBeforeUse(); + appendStrBuf(c); state = transition(state, Tokenizer.BOGUS_COMMENT, reconsume, pos); continue stateloop; case '>': @@ -1768,7 +1803,8 @@ public class Tokenizer implements Locator { * Set that attribute's name to the current * input character, */ - clearStrBufAndAppend(c); + clearStrBufBeforeUse(); + appendStrBuf(c); /* * and its value to the empty string. */ @@ -1914,7 +1950,7 @@ public class Tokenizer implements Locator { * attribute value (double-quoted) state. */ // CPPONLY: attributeLine = line; - clearStrBuf(); + clearStrBufBeforeUse(); state = transition(state, Tokenizer.ATTRIBUTE_VALUE_DOUBLE_QUOTED, reconsume, pos); break beforeattributevalueloop; // continue stateloop; @@ -1925,7 +1961,7 @@ public class Tokenizer implements Locator { * input character. */ // CPPONLY: attributeLine = line; - clearStrBuf(); + clearStrBufBeforeUse(); reconsume = true; state = transition(state, Tokenizer.ATTRIBUTE_VALUE_UNQUOTED, reconsume, pos); noteUnquotedAttributeValue(); @@ -1936,7 +1972,7 @@ public class Tokenizer implements Locator { * value (single-quoted) state. */ // CPPONLY: attributeLine = line; - clearStrBuf(); + clearStrBufBeforeUse(); state = transition(state, Tokenizer.ATTRIBUTE_VALUE_SINGLE_QUOTED, reconsume, pos); continue stateloop; case '>': @@ -1980,7 +2016,8 @@ public class Tokenizer implements Locator { * character to the current attribute's value. */ // CPPONLY: attributeLine = line; - clearStrBufAndAppend(c); + clearStrBufBeforeUse(); + appendStrBuf(c); /* * Switch to the attribute value (unquoted) * state. @@ -2023,7 +2060,8 @@ public class Tokenizer implements Locator { * additional allowed character being U+0022 * QUOTATION MARK ("). */ - clearCharRefBufAndAppend(c); + assert charRefBufLen == 0: "charRefBufLen not reset after previous use!"; + appendCharRefBuf(c); setAdditionalAndRememberAmpersandLocation('\"'); returnState = state; state = transition(state, Tokenizer.CONSUME_CHARACTER_REFERENCE, reconsume, pos); @@ -2192,7 +2230,8 @@ public class Tokenizer implements Locator { * additional allowed character being U+003E * GREATER-THAN SIGN (>) */ - clearCharRefBufAndAppend(c); + assert charRefBufLen == 0: "charRefBufLen not reset after previous use!"; + appendCharRefBuf(c); setAdditionalAndRememberAmpersandLocation('>'); returnState = state; state = transition(state, Tokenizer.CONSUME_CHARACTER_REFERENCE, reconsume, pos); @@ -2331,7 +2370,8 @@ public class Tokenizer implements Locator { * Set that attribute's name to the current * input character, */ - clearStrBufAndAppend(c); + clearStrBufBeforeUse(); + appendStrBuf(c); /* * and its value to the empty string. */ @@ -2377,19 +2417,22 @@ public class Tokenizer implements Locator { */ switch (c) { case '-': - clearStrBufAndAppend(c); + clearStrBufBeforeUse(); + appendStrBuf(c); state = transition(state, Tokenizer.MARKUP_DECLARATION_HYPHEN, reconsume, pos); break markupdeclarationopenloop; // continue stateloop; case 'd': case 'D': - clearStrBufAndAppend(c); + clearStrBufBeforeUse(); + appendStrBuf(c); index = 0; state = transition(state, Tokenizer.MARKUP_DECLARATION_OCTYPE, reconsume, pos); continue stateloop; case '[': if (tokenHandler.cdataSectionAllowed()) { - clearStrBufAndAppend(c); + clearStrBufBeforeUse(); + appendStrBuf(c); index = 0; state = transition(state, Tokenizer.CDATA_START, reconsume, pos); continue stateloop; @@ -2397,7 +2440,7 @@ public class Tokenizer implements Locator { // else fall through default: errBogusComment(); - clearStrBuf(); + clearStrBufBeforeUse(); reconsume = true; state = transition(state, Tokenizer.BOGUS_COMMENT, reconsume, pos); continue stateloop; @@ -2414,7 +2457,7 @@ public class Tokenizer implements Locator { case '\u0000': break stateloop; case '-': - clearStrBuf(); + clearStrBufAfterOneHyphen(); state = transition(state, Tokenizer.COMMENT_START, reconsume, pos); break markupdeclarationhyphenloop; // continue stateloop; @@ -2768,6 +2811,7 @@ public class Tokenizer implements Locator { index++; continue; } else { + clearStrBufAfterUse(); cstart = pos; // start coalescing reconsume = true; state = transition(state, Tokenizer.CDATA_SECTION, reconsume, pos); @@ -2881,7 +2925,8 @@ public class Tokenizer implements Locator { * + additional allowed character being U+0027 * APOSTROPHE ('). */ - clearCharRefBufAndAppend(c); + assert charRefBufLen == 0: "charRefBufLen not reset after previous use!"; + appendCharRefBuf(c); setAdditionalAndRememberAmpersandLocation('\''); returnState = state; state = transition(state, Tokenizer.CONSUME_CHARACTER_REFERENCE, reconsume, pos); @@ -3229,6 +3274,8 @@ public class Tokenizer implements Locator { charRefBufLen - charRefBufMark); } } + // charRefBufLen will be zeroed below! + // Check if we broke out early with c being the last // character that matched as opposed to being the // first one that didn't match. In the case of an @@ -3236,6 +3283,7 @@ public class Tokenizer implements Locator { // *after* the current character and the current // character shouldn't be reconsumed. boolean earlyBreak = (c == ';' && charRefBufMark == charRefBufLen); + charRefBufLen = 0; if ((returnState & DATA_AND_RCDATA_MASK) == 0) { cstart = earlyBreak ? pos + 1 : pos; } @@ -3374,6 +3422,8 @@ public class Tokenizer implements Locator { // WARNING FALLTHRU CASE TRANSITION: DON'T REORDER case HANDLE_NCR_VALUE: // WARNING previous state sets reconsume + // We are not going to emit the contents of charRefBuf. + charRefBufLen = 0; // XXX inline this case if the method size can take it handleNcrValue(returnState); state = transition(state, returnState, reconsume, pos); @@ -3520,7 +3570,8 @@ public class Tokenizer implements Locator { /* * Switch to the bogus comment state. */ - clearStrBufAndAppend('\n'); + clearStrBufBeforeUse(); + appendStrBuf('\n'); state = transition(state, Tokenizer.BOGUS_COMMENT, reconsume, pos); break stateloop; case '\n': @@ -3530,7 +3581,8 @@ public class Tokenizer implements Locator { /* * Switch to the bogus comment state. */ - clearStrBufAndAppend('\n'); + clearStrBufBeforeUse(); + appendStrBuf(c); state = transition(state, Tokenizer.BOGUS_COMMENT, reconsume, pos); continue stateloop; case '\u0000': @@ -3550,7 +3602,8 @@ public class Tokenizer implements Locator { /* * set its tag name to the input character, */ - clearStrBufAndAppend(c); + clearStrBufBeforeUse(); + appendStrBuf(c); /* * then switch to the tag name state. (Don't * emit the token yet; further details will be @@ -3564,7 +3617,8 @@ public class Tokenizer implements Locator { /* * Switch to the bogus comment state. */ - clearStrBufAndAppend(c); + clearStrBufBeforeUse(); + appendStrBuf(c); state = transition(state, Tokenizer.BOGUS_COMMENT, reconsume, pos); continue stateloop; } @@ -3587,7 +3641,8 @@ public class Tokenizer implements Locator { * reference in RCDATA state. */ flushChars(buf, pos); - clearCharRefBufAndAppend(c); + assert charRefBufLen == 0: "charRefBufLen not reset after previous use!"; + appendCharRefBuf(c); setAdditionalAndRememberAmpersandLocation('\u0000'); returnState = state; state = transition(state, Tokenizer.CONSUME_CHARACTER_REFERENCE, reconsume, pos); @@ -3672,7 +3727,7 @@ public class Tokenizer implements Locator { * data end tag open state. */ index = 0; - clearStrBuf(); + clearStrBufBeforeUse(); state = transition(state, Tokenizer.NON_DATA_END_TAG_NAME, reconsume, pos); break rawtextrcdatalessthansignloop; // FALL THRU continue stateloop; @@ -3701,7 +3756,7 @@ public class Tokenizer implements Locator { c = checkChar(buf, pos); /* * ASSERT! when entering this state, set index to 0 and - * call clearStrBuf() assert (contentModelElement != + * call clearStrBufBeforeUse() assert (contentModelElement != * null); Let's implement the above without lookahead. * strBuf is the 'temporary buffer'. */ @@ -3734,6 +3789,7 @@ public class Tokenizer implements Locator { switch (c) { case '\r': silentCarriageReturn(); + clearStrBufAfterUse(); // strBuf not used state = transition(state, Tokenizer.BEFORE_ATTRIBUTE_NAME, reconsume, pos); break stateloop; case '\n': @@ -3749,6 +3805,7 @@ public class Tokenizer implements Locator { * appropriate end tag token, then switch to * the before attribute name state. */ + clearStrBufAfterUse(); // strBuf not used state = transition(state, Tokenizer.BEFORE_ATTRIBUTE_NAME, reconsume, pos); continue stateloop; case '/': @@ -3758,6 +3815,7 @@ public class Tokenizer implements Locator { * then switch to the self-closing start tag * state. */ + clearStrBufAfterUse(); // strBuf not used state = transition(state, Tokenizer.SELF_CLOSING_START_TAG, reconsume, pos); continue stateloop; case '>': @@ -3767,6 +3825,7 @@ public class Tokenizer implements Locator { * end tag token, then emit the current tag * token and switch to the data state. */ + clearStrBufAfterUse(); // strBuf not used state = transition(state, emitCurrentTagToken(false, pos), reconsume, pos); if (shouldSuspend) { break stateloop; @@ -3941,7 +4000,7 @@ public class Tokenizer implements Locator { * data end tag open state. */ index = 0; - clearStrBuf(); + clearStrBufBeforeUse(); state = transition(state, Tokenizer.NON_DATA_END_TAG_NAME, reconsume, pos); continue stateloop; case '!': @@ -4199,7 +4258,7 @@ public class Tokenizer implements Locator { * data escaped end tag open state. */ index = 0; - clearStrBuf(); + clearStrBufBeforeUse(); returnState = Tokenizer.SCRIPT_DATA_ESCAPED; state = transition(state, Tokenizer.NON_DATA_END_TAG_NAME, reconsume, pos); continue stateloop; @@ -4681,7 +4740,8 @@ public class Tokenizer implements Locator { * Set the token's name name to the current * input character. */ - clearStrBufAndAppend(c); + clearStrBufBeforeUse(); + appendStrBuf(c); /* * Switch to the DOCTYPE name state. */ @@ -4902,7 +4962,7 @@ public class Tokenizer implements Locator { * Set the DOCTYPE token's public identifier to * the empty string (not missing), */ - clearStrBuf(); + clearStrBufBeforeUse(); /* * then switch to the DOCTYPE public identifier * (double-quoted) state. @@ -4918,7 +4978,7 @@ public class Tokenizer implements Locator { * Set the DOCTYPE token's public identifier to * the empty string (not missing), */ - clearStrBuf(); + clearStrBufBeforeUse(); /* * then switch to the DOCTYPE public identifier * (single-quoted) state. @@ -4989,7 +5049,7 @@ public class Tokenizer implements Locator { * token's public identifier to the empty string * (not missing), */ - clearStrBuf(); + clearStrBufBeforeUse(); /* * then switch to the DOCTYPE public identifier * (double-quoted) state. @@ -5003,7 +5063,7 @@ public class Tokenizer implements Locator { * public identifier to the empty string (not * missing), */ - clearStrBuf(); + clearStrBufBeforeUse(); /* * then switch to the DOCTYPE public identifier * (single-quoted) state. @@ -5154,7 +5214,7 @@ public class Tokenizer implements Locator { * Set the DOCTYPE token's system identifier to * the empty string (not missing), */ - clearStrBuf(); + clearStrBufBeforeUse(); /* * then switch to the DOCTYPE system identifier * (double-quoted) state. @@ -5170,7 +5230,7 @@ public class Tokenizer implements Locator { * Set the DOCTYPE token's system identifier to * the empty string (not missing), */ - clearStrBuf(); + clearStrBufBeforeUse(); /* * then switch to the DOCTYPE system identifier * (single-quoted) state. @@ -5235,7 +5295,7 @@ public class Tokenizer implements Locator { * token's system identifier to the empty string * (not missing), */ - clearStrBuf(); + clearStrBufBeforeUse(); /* * then switch to the DOCTYPE system identifier * (double-quoted) state. @@ -5249,7 +5309,7 @@ public class Tokenizer implements Locator { * system identifier to the empty string (not * missing), */ - clearStrBuf(); + clearStrBufBeforeUse(); /* * then switch to the DOCTYPE system identifier * (single-quoted) state. @@ -5498,7 +5558,7 @@ public class Tokenizer implements Locator { * Set the DOCTYPE token's system identifier to * the empty string (not missing), */ - clearStrBuf(); + clearStrBufBeforeUse(); /* * then switch to the DOCTYPE public identifier * (double-quoted) state. @@ -5514,7 +5574,7 @@ public class Tokenizer implements Locator { * Set the DOCTYPE token's public identifier to * the empty string (not missing), */ - clearStrBuf(); + clearStrBufBeforeUse(); /* * then switch to the DOCTYPE public identifier * (single-quoted) state. @@ -5585,7 +5645,7 @@ public class Tokenizer implements Locator { * token's system identifier to the empty string * (not missing), */ - clearStrBuf(); + clearStrBufBeforeUse(); /* * then switch to the DOCTYPE system identifier * (double-quoted) state. @@ -5598,7 +5658,7 @@ public class Tokenizer implements Locator { * system identifier to the empty string (not * missing), */ - clearStrBuf(); + clearStrBufBeforeUse(); /* * then switch to the DOCTYPE system identifier * (single-quoted) state. @@ -5814,6 +5874,9 @@ public class Tokenizer implements Locator { // ]NOCPP] private void initDoctypeFields() { + // Discard the characters "DOCTYPE" accumulated as a potential bogus + // comment into strBuf. + clearStrBufAfterUse(); doctypeName = ""; if (systemIdentifier != null) { Portability.releaseString(systemIdentifier); @@ -6101,7 +6164,6 @@ public class Tokenizer implements Locator { break eofloop; case MARKUP_DECLARATION_OPEN: errBogusComment(); - clearStrBuf(); emitComment(0, 0); break eofloop; case MARKUP_DECLARATION_HYPHEN: @@ -6457,6 +6519,7 @@ public class Tokenizer implements Locator { charRefBufLen - charRefBufMark); } } + charRefBufLen = 0; state = returnState; continue eofloop; /* @@ -6636,7 +6699,7 @@ public class Tokenizer implements Locator { } public void resetToDataState() { - strBufLen = 0; + clearStrBufAfterUse(); charRefBufLen = 0; stateSave = Tokenizer.DATA; // line = 1; XXX line numbers diff --git a/parser/html/nsHtml5Tokenizer.cpp b/parser/html/nsHtml5Tokenizer.cpp index 24b3604d40b8..550d2da8ffac 100644 --- a/parser/html/nsHtml5Tokenizer.cpp +++ b/parser/html/nsHtml5Tokenizer.cpp @@ -217,26 +217,24 @@ nsHtml5Tokenizer::emitOrAppendCharRefBuf(int32_t returnState) } else { if (charRefBufLen > 0) { tokenHandler->characters(charRefBuf, 0, charRefBufLen); + charRefBufLen = 0; } } } -void -nsHtml5Tokenizer::appendStrBuf(char16_t c) -{ - strBuf[strBufLen++] = c; -} - nsString* nsHtml5Tokenizer::strBufToString() { - return nsHtml5Portability::newStringFromBuffer(strBuf, 0, strBufLen, tokenHandler); + nsString* str = nsHtml5Portability::newStringFromBuffer(strBuf, 0, strBufLen, tokenHandler); + clearStrBufAfterUse(); + return str; } void nsHtml5Tokenizer::strBufToDoctypeName() { doctypeName = nsHtml5Portability::newLocalNameFromBuffer(strBuf, 0, strBufLen, interner); + clearStrBufAfterUse(); } void @@ -244,26 +242,29 @@ nsHtml5Tokenizer::emitStrBuf() { if (strBufLen > 0) { tokenHandler->characters(strBuf, 0, strBufLen); + clearStrBufAfterUse(); } } void nsHtml5Tokenizer::appendStrBuf(char16_t* buffer, int32_t offset, int32_t length) { - int32_t reqLen = strBufLen + length; - if (strBuf.length < reqLen) { - jArray newBuf = jArray::newJArray(reqLen + (reqLen >> 1)); - nsHtml5ArrayCopy::arraycopy(strBuf, newBuf, strBuf.length); - strBuf = newBuf; + int32_t newLen = strBufLen + length; + MOZ_ASSERT(newLen <= strBuf.length, "Previous buffer length insufficient."); + if (MOZ_UNLIKELY(strBuf.length < newLen)) { + if (MOZ_UNLIKELY(!EnsureBufferSpace(length))) { + MOZ_CRASH("Unable to recover from buffer reallocation failure"); + } } nsHtml5ArrayCopy::arraycopy(buffer, offset, strBuf, strBufLen, length); - strBufLen = reqLen; + strBufLen = newLen; } void nsHtml5Tokenizer::emitComment(int32_t provisionalHyphens, int32_t pos) { tokenHandler->comment(strBuf, 0, strBufLen - provisionalHyphens); + clearStrBufAfterUse(); cstart = pos + 1; } @@ -280,6 +281,7 @@ void nsHtml5Tokenizer::strBufToElementNameString() { tagName = nsHtml5ElementName::elementNameByBuffer(strBuf, 0, strBufLen, interner); + clearStrBufAfterUse(); } int32_t @@ -321,6 +323,7 @@ void nsHtml5Tokenizer::attributeNameComplete() { attributeName = nsHtml5AttributeName::nameByBuffer(strBuf, 0, strBufLen, interner); + clearStrBufAfterUse(); if (!attributes) { attributes = new nsHtml5HtmlAttributes(0); } @@ -338,6 +341,8 @@ nsHtml5Tokenizer::addAttributeWithoutValue() if (attributeName) { attributes->addAttribute(attributeName, nsHtml5Portability::newEmptyString(), attributeLine); attributeName = nullptr; + } else { + clearStrBufAfterUse(); } } @@ -432,7 +437,8 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu switch(c) { case '&': { flushChars(buf, pos); - clearCharRefBufAndAppend(c); + MOZ_ASSERT(!charRefBufLen, "charRefBufLen not reset after previous use!"); + appendCharRefBuf(c); setAdditionalAndRememberAmpersandLocation('\0'); returnState = state; state = P::transition(mViewSource, NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE, reconsume, pos); @@ -469,12 +475,14 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu c = checkChar(buf, pos); if (c >= 'A' && c <= 'Z') { endTag = false; - clearStrBufAndAppend((char16_t) (c + 0x20)); + clearStrBufBeforeUse(); + appendStrBuf((char16_t) (c + 0x20)); state = P::transition(mViewSource, NS_HTML5TOKENIZER_TAG_NAME, reconsume, pos); NS_HTML5_BREAK(tagopenloop); } else if (c >= 'a' && c <= 'z') { endTag = false; - clearStrBufAndAppend(c); + clearStrBufBeforeUse(); + appendStrBuf(c); state = P::transition(mViewSource, NS_HTML5TOKENIZER_TAG_NAME, reconsume, pos); NS_HTML5_BREAK(tagopenloop); } @@ -495,7 +503,8 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu if (P::reportErrors) { errProcessingInstruction(); } - clearStrBufAndAppend(c); + clearStrBufBeforeUse(); + appendStrBuf(c); state = P::transition(mViewSource, NS_HTML5TOKENIZER_BOGUS_COMMENT, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } @@ -622,7 +631,8 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu c += 0x20; } attributeLine = line; - clearStrBufAndAppend(c); + clearStrBufBeforeUse(); + appendStrBuf(c); state = P::transition(mViewSource, NS_HTML5TOKENIZER_ATTRIBUTE_NAME, reconsume, pos); NS_HTML5_BREAK(beforeattributenameloop); } @@ -715,13 +725,13 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu } case '\"': { attributeLine = line; - clearStrBuf(); + clearStrBufBeforeUse(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_DOUBLE_QUOTED, reconsume, pos); NS_HTML5_BREAK(beforeattributevalueloop); } case '&': { attributeLine = line; - clearStrBuf(); + clearStrBufBeforeUse(); reconsume = true; state = P::transition(mViewSource, NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_UNQUOTED, reconsume, pos); @@ -729,7 +739,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu } case '\'': { attributeLine = line; - clearStrBuf(); + clearStrBufBeforeUse(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_SINGLE_QUOTED, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } @@ -756,7 +766,8 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu } default: { attributeLine = line; - clearStrBufAndAppend(c); + clearStrBufBeforeUse(); + appendStrBuf(c); state = P::transition(mViewSource, NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_UNQUOTED, reconsume, pos); NS_HTML5_CONTINUE(stateloop); @@ -782,7 +793,8 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu NS_HTML5_BREAK(attributevaluedoublequotedloop); } case '&': { - clearCharRefBufAndAppend(c); + MOZ_ASSERT(!charRefBufLen, "charRefBufLen not reset after previous use!"); + appendCharRefBuf(c); setAdditionalAndRememberAmpersandLocation('\"'); returnState = state; state = P::transition(mViewSource, NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE, reconsume, pos); @@ -902,7 +914,8 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu NS_HTML5_CONTINUE(stateloop); } case '&': { - clearCharRefBufAndAppend(c); + MOZ_ASSERT(!charRefBufLen, "charRefBufLen not reset after previous use!"); + appendCharRefBuf(c); setAdditionalAndRememberAmpersandLocation('>'); returnState = state; state = P::transition(mViewSource, NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE, reconsume, pos); @@ -987,7 +1000,8 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu if (c >= 'A' && c <= 'Z') { c += 0x20; } - clearStrBufAndAppend(c); + clearStrBufBeforeUse(); + appendStrBuf(c); state = P::transition(mViewSource, NS_HTML5TOKENIZER_ATTRIBUTE_NAME, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } @@ -1002,20 +1016,23 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu c = checkChar(buf, pos); switch(c) { case '-': { - clearStrBufAndAppend(c); + clearStrBufBeforeUse(); + appendStrBuf(c); state = P::transition(mViewSource, NS_HTML5TOKENIZER_MARKUP_DECLARATION_HYPHEN, reconsume, pos); NS_HTML5_BREAK(markupdeclarationopenloop); } case 'd': case 'D': { - clearStrBufAndAppend(c); + clearStrBufBeforeUse(); + appendStrBuf(c); index = 0; state = P::transition(mViewSource, NS_HTML5TOKENIZER_MARKUP_DECLARATION_OCTYPE, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } case '[': { if (tokenHandler->cdataSectionAllowed()) { - clearStrBufAndAppend(c); + clearStrBufBeforeUse(); + appendStrBuf(c); index = 0; state = P::transition(mViewSource, NS_HTML5TOKENIZER_CDATA_START, reconsume, pos); NS_HTML5_CONTINUE(stateloop); @@ -1025,7 +1042,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu if (P::reportErrors) { errBogusComment(); } - clearStrBuf(); + clearStrBufBeforeUse(); reconsume = true; state = P::transition(mViewSource, NS_HTML5TOKENIZER_BOGUS_COMMENT, reconsume, pos); NS_HTML5_CONTINUE(stateloop); @@ -1045,7 +1062,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu NS_HTML5_BREAK(stateloop); } case '-': { - clearStrBuf(); + clearStrBufAfterOneHyphen(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_COMMENT_START, reconsume, pos); NS_HTML5_BREAK(markupdeclarationhyphenloop); } @@ -1309,6 +1326,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu index++; continue; } else { + clearStrBufAfterUse(); cstart = pos; reconsume = true; state = P::transition(mViewSource, NS_HTML5TOKENIZER_CDATA_SECTION, reconsume, pos); @@ -1416,7 +1434,8 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu NS_HTML5_CONTINUE(stateloop); } case '&': { - clearCharRefBufAndAppend(c); + MOZ_ASSERT(!charRefBufLen, "charRefBufLen not reset after previous use!"); + appendCharRefBuf(c); setAdditionalAndRememberAmpersandLocation('\''); returnState = state; state = P::transition(mViewSource, NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE, reconsume, pos); @@ -1648,6 +1667,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu } } bool earlyBreak = (c == ';' && charRefBufMark == charRefBufLen); + charRefBufLen = 0; if (!(returnState & NS_HTML5TOKENIZER_DATA_AND_RCDATA_MASK)) { cstart = earlyBreak ? pos + 1 : pos; } @@ -1741,6 +1761,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu decimalloop_end: ; } case NS_HTML5TOKENIZER_HANDLE_NCR_VALUE: { + charRefBufLen = 0; handleNcrValue(returnState); state = P::transition(mViewSource, returnState, reconsume, pos); NS_HTML5_CONTINUE(stateloop); @@ -1866,7 +1887,8 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu if (P::reportErrors) { errGarbageAfterLtSlash(); } - clearStrBufAndAppend('\n'); + clearStrBufBeforeUse(); + appendStrBuf('\n'); state = P::transition(mViewSource, NS_HTML5TOKENIZER_BOGUS_COMMENT, reconsume, pos); NS_HTML5_BREAK(stateloop); } @@ -1875,7 +1897,8 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu if (P::reportErrors) { errGarbageAfterLtSlash(); } - clearStrBufAndAppend('\n'); + clearStrBufBeforeUse(); + appendStrBuf(c); state = P::transition(mViewSource, NS_HTML5TOKENIZER_BOGUS_COMMENT, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } @@ -1888,14 +1911,16 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu } if (c >= 'a' && c <= 'z') { endTag = true; - clearStrBufAndAppend(c); + clearStrBufBeforeUse(); + appendStrBuf(c); state = P::transition(mViewSource, NS_HTML5TOKENIZER_TAG_NAME, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } else { if (P::reportErrors) { errGarbageAfterLtSlash(); } - clearStrBufAndAppend(c); + clearStrBufBeforeUse(); + appendStrBuf(c); state = P::transition(mViewSource, NS_HTML5TOKENIZER_BOGUS_COMMENT, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } @@ -1915,7 +1940,8 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu switch(c) { case '&': { flushChars(buf, pos); - clearCharRefBufAndAppend(c); + MOZ_ASSERT(!charRefBufLen, "charRefBufLen not reset after previous use!"); + appendCharRefBuf(c); setAdditionalAndRememberAmpersandLocation('\0'); returnState = state; state = P::transition(mViewSource, NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE, reconsume, pos); @@ -1989,7 +2015,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu switch(c) { case '/': { index = 0; - clearStrBuf(); + clearStrBufBeforeUse(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_NON_DATA_END_TAG_NAME, reconsume, pos); NS_HTML5_BREAK(rawtextrcdatalessthansignloop); } @@ -2033,6 +2059,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu switch(c) { case '\r': { silentCarriageReturn(); + clearStrBufAfterUse(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME, reconsume, pos); NS_HTML5_BREAK(stateloop); } @@ -2042,14 +2069,17 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu case ' ': case '\t': case '\f': { + clearStrBufAfterUse(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } case '/': { + clearStrBufAfterUse(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } case '>': { + clearStrBufAfterUse(); state = P::transition(mViewSource, emitCurrentTagToken(false, pos), reconsume, pos); if (shouldSuspend) { NS_HTML5_BREAK(stateloop); @@ -2193,7 +2223,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu switch(c) { case '/': { index = 0; - clearStrBuf(); + clearStrBufBeforeUse(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_NON_DATA_END_TAG_NAME, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } @@ -2378,7 +2408,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu switch(c) { case '/': { index = 0; - clearStrBuf(); + clearStrBufBeforeUse(); returnState = NS_HTML5TOKENIZER_SCRIPT_DATA_ESCAPED; state = P::transition(mViewSource, NS_HTML5TOKENIZER_NON_DATA_END_TAG_NAME, reconsume, pos); NS_HTML5_CONTINUE(stateloop); @@ -2734,7 +2764,8 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu if (c >= 'A' && c <= 'Z') { c += 0x20; } - clearStrBufAndAppend(c); + clearStrBufBeforeUse(); + appendStrBuf(c); state = P::transition(mViewSource, NS_HTML5TOKENIZER_DOCTYPE_NAME, reconsume, pos); NS_HTML5_BREAK(beforedoctypenameloop); } @@ -2886,7 +2917,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu if (P::reportErrors) { errNoSpaceBetweenDoctypePublicKeywordAndQuote(); } - clearStrBuf(); + clearStrBufBeforeUse(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } @@ -2894,7 +2925,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu if (P::reportErrors) { errNoSpaceBetweenDoctypePublicKeywordAndQuote(); } - clearStrBuf(); + clearStrBufBeforeUse(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } @@ -2936,12 +2967,12 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu continue; } case '\"': { - clearStrBuf(); + clearStrBufBeforeUse(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED, reconsume, pos); NS_HTML5_BREAK(beforedoctypepublicidentifierloop); } case '\'': { - clearStrBuf(); + clearStrBufBeforeUse(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } @@ -3034,7 +3065,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu if (P::reportErrors) { errNoSpaceBetweenPublicAndSystemIds(); } - clearStrBuf(); + clearStrBufBeforeUse(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } @@ -3042,7 +3073,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu if (P::reportErrors) { errNoSpaceBetweenPublicAndSystemIds(); } - clearStrBuf(); + clearStrBufBeforeUse(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } @@ -3080,12 +3111,12 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu NS_HTML5_CONTINUE(stateloop); } case '\"': { - clearStrBuf(); + clearStrBufBeforeUse(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED, reconsume, pos); NS_HTML5_BREAK(betweendoctypepublicandsystemidentifiersloop); } case '\'': { - clearStrBuf(); + clearStrBufBeforeUse(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } @@ -3257,7 +3288,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu if (P::reportErrors) { errNoSpaceBetweenDoctypeSystemKeywordAndQuote(); } - clearStrBuf(); + clearStrBufBeforeUse(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } @@ -3265,7 +3296,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu if (P::reportErrors) { errNoSpaceBetweenDoctypeSystemKeywordAndQuote(); } - clearStrBuf(); + clearStrBufBeforeUse(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } @@ -3307,12 +3338,12 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu continue; } case '\"': { - clearStrBuf(); + clearStrBufBeforeUse(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } case '\'': { - clearStrBuf(); + clearStrBufBeforeUse(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED, reconsume, pos); NS_HTML5_BREAK(beforedoctypesystemidentifierloop); } @@ -3460,6 +3491,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu void nsHtml5Tokenizer::initDoctypeFields() { + clearStrBufAfterUse(); doctypeName = nsHtml5Atoms::emptystring; if (systemIdentifier) { nsHtml5Portability::releaseString(systemIdentifier); @@ -3612,7 +3644,6 @@ nsHtml5Tokenizer::eof() } case NS_HTML5TOKENIZER_MARKUP_DECLARATION_OPEN: { errBogusComment(); - clearStrBuf(); emitComment(0, 0); NS_HTML5_BREAK(eofloop); } @@ -3818,6 +3849,7 @@ nsHtml5Tokenizer::eof() tokenHandler->characters(charRefBuf, charRefBufMark, charRefBufLen - charRefBufMark); } } + charRefBufLen = 0; state = returnState; NS_HTML5_CONTINUE(eofloop); } @@ -3940,7 +3972,7 @@ nsHtml5Tokenizer::isInDataState() void nsHtml5Tokenizer::resetToDataState() { - strBufLen = 0; + clearStrBufAfterUse(); charRefBufLen = 0; stateSave = NS_HTML5TOKENIZER_DATA; lastCR = false; diff --git a/parser/html/nsHtml5Tokenizer.h b/parser/html/nsHtml5Tokenizer.h index 6a6a8ed39b78..9848a502b3a8 100644 --- a/parser/html/nsHtml5Tokenizer.h +++ b/parser/html/nsHtml5Tokenizer.h @@ -158,28 +158,40 @@ class nsHtml5Tokenizer private: inline void appendCharRefBuf(char16_t c) { + MOZ_RELEASE_ASSERT(charRefBufLen < charRefBuf.length, "Attempted to overrun charRefBuf!"); charRefBuf[charRefBufLen++] = c; } - inline void clearCharRefBufAndAppend(char16_t c) - { - charRefBuf[0] = c; - charRefBufLen = 1; - } - void emitOrAppendCharRefBuf(int32_t returnState); - inline void clearStrBufAndAppend(char16_t c) - { - strBuf[0] = c; - strBufLen = 1; - } - - inline void clearStrBuf() + inline void clearStrBufAfterUse() { strBufLen = 0; } - void appendStrBuf(char16_t c); + inline void clearStrBufBeforeUse() + { + MOZ_ASSERT(!strBufLen, "strBufLen not reset after previous use!"); + strBufLen = 0; + } + + inline void clearStrBufAfterOneHyphen() + { + MOZ_ASSERT(strBufLen == 1, "strBufLen length not one!"); + MOZ_ASSERT(strBuf[0] == '-', "strBuf does not start with a hyphen!"); + strBufLen = 0; + } + + inline void appendStrBuf(char16_t c) + { + MOZ_ASSERT(strBufLen < strBuf.length, "Previous buffer length insufficient."); + if (MOZ_UNLIKELY(strBufLen == strBuf.length)) { + if (MOZ_UNLIKELY(!EnsureBufferSpace(1))) { + MOZ_CRASH("Unable to recover from buffer reallocation failure"); + } + } + strBuf[strBufLen++] = c; + } + protected: nsString* strBufToString(); private: @@ -200,6 +212,7 @@ class nsHtml5Tokenizer inline void appendCharRefBufToStrBuf() { appendStrBuf(charRefBuf, 0, charRefBufLen); + charRefBufLen = 0; } void emitComment(int32_t provisionalHyphens, int32_t pos); diff --git a/parser/html/nsHtml5TreeBuilderCppSupplement.h b/parser/html/nsHtml5TreeBuilderCppSupplement.h index 4cd030a3e7b4..ce040183f57b 100644 --- a/parser/html/nsHtml5TreeBuilderCppSupplement.h +++ b/parser/html/nsHtml5TreeBuilderCppSupplement.h @@ -955,8 +955,8 @@ nsHtml5TreeBuilder::elementPopped(int32_t aNamespace, nsIAtom* aName, nsIContent void nsHtml5TreeBuilder::accumulateCharacters(const char16_t* aBuf, int32_t aStart, int32_t aLength) { - MOZ_ASSERT(charBufferLen + aLength <= charBuffer.length, - "About to memcpy past the end of the buffer!"); + MOZ_RELEASE_ASSERT(charBufferLen + aLength <= charBuffer.length, + "About to memcpy past the end of the buffer!"); memcpy(charBuffer + charBufferLen, aBuf + aStart, sizeof(char16_t) * aLength); charBufferLen += aLength; } From d4aabe37f6a74c415b48d2e87d6bccc2e37e5a5f Mon Sep 17 00:00:00 2001 From: Avi Halachmi Date: Tue, 27 Sep 2016 13:52:01 +0300 Subject: [PATCH 026/102] Bug 1305489: talos: pageloader: scrolltest: fix where the URL contains %. r=jmaher --- .../talos/pageloader/chrome/pageloader.js | 2 +- testing/talos/talos/pageloader/install.rdf | 2 +- .../talos/pageloader/pageloader-signed.xpi | Bin 29177 -> 28966 bytes 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/talos/talos/pageloader/chrome/pageloader.js b/testing/talos/talos/pageloader/chrome/pageloader.js index 0d61bcce5eb6..6d3f8592c4eb 100644 --- a/testing/talos/talos/pageloader/chrome/pageloader.js +++ b/testing/talos/talos/pageloader/chrome/pageloader.js @@ -873,7 +873,7 @@ function plLoadURLsFromURI(manifestUri) { // Note that if we have the scrollTest flag but the item already has "%", then we do // nothing (the scroll test will not execute, and the page will report with its // own tpRecordTime and not the one from the scroll test). - if (scrollTest && items[0].indexOf("%") < 0) { + if (scrollTest && items.length == 1) { // scroll enabled and no "%" items.unshift("%"); flags |= EXECUTE_SCROLL_TEST; } diff --git a/testing/talos/talos/pageloader/install.rdf b/testing/talos/talos/pageloader/install.rdf index dbd634dbaa64..861b9b092951 100644 --- a/testing/talos/talos/pageloader/install.rdf +++ b/testing/talos/talos/pageloader/install.rdf @@ -4,7 +4,7 @@ xmlns:em="http://www.mozilla.org/2004/em-rdf#"> pageloader@mozilla.org - 1.0.10 + 1.0.12 {ec8030f7-c20a-464f-9b0e-13a3a9e97384} diff --git a/testing/talos/talos/pageloader/pageloader-signed.xpi b/testing/talos/talos/pageloader/pageloader-signed.xpi index 325e71a4c4e742a52f361c6a42cbfd5bcd8bfb16..5888b529b63f82fcc8f5695fb8a430b76186b11b 100644 GIT binary patch delta 13067 zcmaia1ymec)^+0^+$FfXdw?K;;O-V6xVshZ?hu?naCdjt06_x5g1ZHWA7=>Jol|%1eX{{punvYT{~iJo0|WxWg0PhMBn4|L1dkCxAf;GrQh+PG zDzYqgdA{2Kv7_rVN;Q*2Sjakaq(DT*K|fw1MXY}*S<68$3aKP5sYlX*UA57d_sb4@ znRf#Z`+`?)M?lBKu}=HS@m=fjwwE9%R`Rtt8CDKvl^Aj^_(!zV1TfNga2&|)NicS1 zDGUh6QAtU#$p>3-W3)9nFj5L!VnF0wDhe|!Vvuk7l90a+=(eL($WcO=E zL0TK4fX=U4rXL%RJK8fa^?9I`VciA%zSO{s|45yf|FMYQWg!7RJ`60%+Lj z8ZvEU1C~k%0yAbc>58vmq!giuw%=Na99?{+WQ?L4Den7W(o)=IczDZ2Buxr81#+WG zE^*q@O~m>RDVgX`)_#ByVN6{4miuQD##6>DxzU-0Ura~AKekHsSL5W8EA^GMS2br= zIPpC=WNvuAH7l~)TNE%fg+^%Z*iaf9ZTI6$kWq-8+E|*XI8L*XdZDH4T%~;69I&%6 z%v{T~XCg|hS3^3URk1QY95}J2i3$>P%HlBBjlvN}L@s8#=#vJVC(NMZn<$kr>#ZqD zwq$}wRUjj6G7MD8W0#{ouQ|)W>J#OcEQ9sgc;FW)D~G;XlDI1!MI={t_awnhZ?HtO z$fPa*`u*)?F0#7o^4E2>x!X3m!=S*40K~H1FKu+?r!FW>CXJnq?p!$iV6=`${nb~5 zQGE@IDwo|RqUH+#i-Nf_S{jxma# zjVvijW5J=6>uD5%33^Pk;)jQoV>8HmwS$c%s`S?s<0s)dNhckvio={5ik!@-wG)%| zg!>=5^?^ml%d%C@dbQdPH3TN4WV4H^y+WDSE7oLP;t_H9R)D8zuF`Iswt|jF-~fx9 zZK-2>!g4LFGOLG*%)T0{jcR_DX6&X>oy#>EIx@#OmWI}me!!bYBhWO>lusHu-q2b2 zjMfC|-~=VmxO~h)h9B?9t+Lbh!P?o| z&bM}`2l_5*Sjg<$A-V+O)+R9HwcgC*a_`Zvg~XCUce9Z68GjdJPY<+VFQGsh%~TKP zy$*S81JQswJb;pn6}4B7 zrk-C0(48978XMtJcT?0D?{dDi4i5ipA?wvC3G|cj7ncny0HaJ-8KgWtFtaUvEl%+j z5Tf%$LIJV>l`Skf)b%!_@9Qd;P9U-M$%qrO1mAbnPIPW3>m9+i=(TvWx)2^29Ythf zTr4l;@(1d3xoe=Wxdypj(fZ#x7um8^{c!jYsyV3u1x_YjG^sr)gIBxNgOMEh~(1jvGk= zR}b)GU6g^RDhA#V?R;`Q?SRXKizV;|wB`~G&xUz_hCZCEg0U7RdiXpTVswXaS#A$C z2}U;sheu*nXHA{bd(TjpR#49d;fus5+c%rD4O>;d>E4XI6v$Ax&*afN>4JGXJ( zmqsUfvSZh@JO_65cGD_sSemZ5Bc?8n+{KBhd2iUgVMyyXdV?p6?#Gq~u`sMN&}Kq% z{;sP}eY&(VFiMlmSl=g8Zc{aw=(D!OwXW5cRRvVfFA_NtP3}N_qmMQ4Ey0<_5 znm=aPXToYu22Ni46C@6(=SX}& zgiw#Jnq&!rsAV?CKopgfg!1*o=OBWnrc3DSS@8>G7n4dUcl6r~K2KNuun`F^au$8) zHyI;MOfHa;Uu`$ln`ioUL83I5S_UOG8e6V>3?6O>>Grh}I4UIgX9M;mR6sL3#0nDy zgLc$?c)X`aOjhx1<%N-$Uelds#=^)fkvR*$579R_FM9{|LHdUUNrE zgun(Dy!YrZ&ebef$3xInP-%A83`q1XT(W!AUA)afsr@7THJw(2Vv4zO#SB@wlXYo& zJ+f$7?S*u#u-=V_<6W<$G0;uJ;Z2o4)I?LjhA2g#LyKu?6~4Y8|BKT1-PUprBb0L3 zw;k)Rxs=X`V*1E5E~`@VKej zrtNquv@f|GZh9QOo6l28fT5d}^1Vw?x)oQdWVf&byDJfYM0#eQ6ewlCdiNz7MG)B- zwt+%5BAy6td3nX3&0v$MNX<;ck{`iRe5_lsfEe5kRf7Zd5KnHn%FJ?dIc25PDl7;| zEO|?6wGzU;pn$Ik-`RYoWha0#GEnq3FTyp>YK#0ZA zhBmBP;s@PMj(*7((weV>;fFbLxKzCm?W1{-F-V776W{p0djSVL=}a~quLv)H4zI$H z_U~gFL}$~_|L|!xxlr5-f+{TFlzX&Z4;&CLuM|c^wcmW#fkOmGNc?l`X@vFWeaM5n zb?O%AE?N|2bVB6S>Z3tUFY}|!Cdltisr)FaOS)Z1w^eh;q=m6`Npw2Zh;9_d>h1SE zKeR54bdl-dxf$TRMK9Ssz%*J>?>(j@jqKNq4}|ezvMy$64M_{~^6h*y)EK(2=h*5O zXI$io2$*9TfG9Rnt83=kX=4E`FB6_nFIwdk9Z5zp5RYK_Kqm(Nksren{7IT!V;2aG zYu_UvYp)|)r!F-c&Vz(tn-0)(4h8hCy!dToK}XfIyTF%&kw{;Ld%rFd@Gv~geHc$F zdDLu;++jjJrJL0ElsC>PNF}*T$UpJBD4<`jRLj<+ht^o2&e$XbI~9HxS~rn5zZ;t! zn>ZVFZHiBIP3~{>FM>3)_g%o=tiykczw}R62L@h(zer*Y&?w;%v<#*I|p3w?WD}uS!|v-`cLgQABQY${Fvav>BY1#kx6l= zJXp0IZQwK!bR>=j?cOMGQD2nrmi=1NF-xf=#YjlVFG_3vn)_C_I__44-KMxseIELY z#?c4_+&5;hy(%zLI9zH%&Z+84J<7g?Tt*7L?J^ zy>_9T347LY9+e!hvY$*CvNz)JtBJhNu=L#U`OyXTH;D<3Bdz787O5CK-W-VQZ;bkU zNqqPeZLO-t_5_o*!}L47QqmZSo94niR!9(t9u@?GeojwOOjuM#>`$3}9=27jQODwk zXw4rss*babWmhW9?{c{r9<2@rQ$PypYeLF|&t%UNX&af4WRo z##T1=ZhyTQL%$;h6g6#Kd^qrOWRAWvxQC*w5uGZX4Z}}sY*Z4F)T?lteh~Xn82!sL7Fjz zTru4tVMh>lzR4X$skL6k9ZJbcVd6{4aZLe9{~PCLwx z$Ml{Dv!t*!=#_%6zKH@Nv$tfjAsQtqVX^__6S-nQej_6=VhJ#-pDaDFXCZ^OKqmMX zeH&fhR8v>NR_X&nOh|ELd(XEg`dCwkH4+BRlG|bJ(6_)lx^%H|L9)ZSZ$f)=WBPm# zQEmuxA)VhKP%Uj+@4r%2lPwn`egnSLQpWJ*xH`fR2kgzZ@#K)PaABa+gae#K7UKsE zL~+&*umDV@2fc8yFCHhWr^yDVYa}1WI`i6=r||dk#ckHS$14 zfh{yFf3TALtCl!9 zmB|XIQ6EAhly1%nOijnmFvgh=?zmI)U+F;m&(=xzZcgo-?QJeh?d%;K?#^zW?r%)L z_AsOnBNfK*DWn-@Po}p8^%*98LAZq*A`^1IrWPh)Ny-hG#yqHP1%h5zksZa&xrPeS z$8M1s`Iv76rVnXTqAw4Y#&+k(Non%JN@{doR94$11Q45;*l{!6g3A;Cf|i3>dG*M> zb9KjFX%_D3eX>6_A<@H?ETNXS*0(S;gz1bm$YK7Cz3#Odi6RhtR4 zqiY!=>{ew_RY+GOIG_igUl3nI-G3lj;cJwScvY*ir!;9L)2k1iBi4T{!Ww;BSmpDv`SI&t`)T}yF21& zpYU_MDxE%Jd*&o#EOJmUll1ZXRoyDD|KtW&juHHlJ<*QcB0!z?3V>acKmMFLJsk+| znY4LEDU}R$pt%8#gTZ1~<~Xn39l;H~Xk#2dA&gJika~dsnNR&|_}*@rV`SL0hXu*y{27lNmc`wZ!N~Rr1 zmkY-iig1t-`p!c2e}HbTCw@m^S}KCD-wy3KVP8O_P77Nrq~VS8<NV!_mK^JqbOlDD5 zNqW|}3H9Ekp&jq?77H3Kn2=%8(hO1*&pie=Ynuco-%}YS=?WIIfhYLV)7JWDpb}tb07kHgkc1ASuQd$w~7H|{-z)7;Nf16{E{9))sa* zr*`w#$jIt3tiR9%YnJ!myrm0-Buas=hLil>iM2@{fWFuN*#8yE_ZN0>F3OcOb^*q% zS7Cj54}PcuHu+C-*?|v;aE-+M4Fr4%ZoW8~;BAJ?lG4dR*MWt^<2MkXuFq)pHVyK0 zU|xWRC=M3^)3)L9u8Rk7|H~|z%vQevj0ry!yl^m-(J`0dMv6tWTr_WWJUDK(|G+^h+`fXXOb9$jp=g^PgTZgLc2U5 zoMg+pi6WVyD4pL;rq}?pA3hhC9&6#ImSxi~Yq-IJFe(xh=n@4xz^89m*Ta-JXy?lI z89jq`z62Ii?c9|e&-0WYXp0zm7bW2Bs8|0Nv!WItS40$++syIxd$YW01IZvlURfDYuS%NqQ7FnPa#Ru;i|OUTB{Nn z43jKk!sX?`qHvN(bt0%Byl{K<{eb0$@CpZtx71M)PMAS zuu0NJC_SZHLZT5e`UuD-16ddn6N>1)aYX%V`p6!R0V;9K@jIMTqe?0E_g5a`YfEkY#AK1uNo1AnX%NU}J6oko!Q z%bG021%JX@V$p(3)N?`X$MW>XksyjHJw8?5Zb(d&mV*xmIFY^K8!-IC^9C>1!fcTI zmHq`$z_;kAvm|^B|ILbTk#$8f`QLPd;qEh(`qwbcg@2f?TD1(InrvhN3q_XXeT%1* zDI!f{gh)4Yxq08tPfWH3-GQGN^TuNGe>RT`mDT);yt>0PvhglaL@^_> z)h3G8MD{#UJ-=*MI)sgsA>rikPxsnFY+{41wt;ELEUo8O?!ii!4M~JqT;kmIJajL- zM!N1J$g_-^D{B?f;Q*gIP%a$*Hksuo;j{Ou%r{Sc9RL~yGNHeV1CSPsi}gKPLmjwn z%gUw@p<1SzxW;}9#e?k3b{3!XY?s_`>`2+zv41JJ!^@#*3l{10Yz@cuWywO$mxfB zc9mrbr5D`Wq_XDvTEC6uB$!}`QR|$1DF#_UP8Sibn{93PV=gS_^iTLoLYJ*Xqva!^ z^L#f?9od~?)j>B;$F+ELQQD=b1(3=;`k?xJlF{4p{IUz_MS*513?2{lIw2KbTwBDj zI*Tnn0V1RCr1w5YOqiuX6hn2)T@H*%xGfWu(l$zx+$b`(SiG8q^giGi`Nl4g7hIujuDwW=_SO+{t4n-+ZbcqtqNp6KImW@A69~wa1?nSYTw)nUa1u zwdarGB7bydbOHpZsdz8gza#Rbs}{h(WPgzba))!U0iJdO=><$mC3`nY`;0DpQwUpVqz+FC?GHfow! zW&cbpuK95!xTb3)-W!A>6uXkXfQ-tf;d(l? zSOQ9=#3$eo*CTiTot$y?jSfV|myb&I&KxQu(VWwBQHAX>efC{NE7AtNL-={EP+X*2 zmg-%s(*%TGNWwF+rUBLHcdBCE%GLuc+Y1-Cbz#D9SrLXrn!!k7N-L$WnI=q3CC2p2 zrZdnFisE%r#AZK>V(@^&28OqNhTLAGXq0>)*Qo*m156!@i5R>z5PKu;8Wh~d-qo`e zDx&iUBH85fQ1stYeGF!*(9Ixt)vc^`LVgD+gQ~o2E zQ+%d8HCk{YGs^}WjoXjc!NP$}7~fZz;^*awP>?EroMWr3G_)mbvn{QSQ^Z3n@PZ-7 z3oBrOeTi3BAOIVScT%7QJc3G3AQ+FjIR>oQ^6%vdlh(;GInWWW({Bqf9$mvxYXJ_%O~(X*11AI^~BWv|z% zesrB=4?_uxTJua^BgFfbvS-e!3gMQQ8%(TVMeIT$hP5^gP0%(0?A{hcHWeRs%?q-| zyIyEl${fsGuMPZ?su7%>F7o``#@{p7V8)TcpZzXSOUfjCTE#OptFKcZT5YzRduytW z$uz)_=*tE(rvZwUcnOd=zf|cL`5NCAe##Ovt)Rx+-2b&&4%Sr_65Cn!?vA-WjFa&> zXM{X^oD)KV!@=n?P#)T2Ro_JaI5mC!1Nu_1y)ff!K~*X*a^32thQIFaKDrDBbt6hK zKX2dE;I#PllDsePB@TEhUx8yU9I2lPzCukd3@?4Y?VeeMc(TN{+V-0~p7)xce?Txr zeyBjb%#poS^!aqIK-aCF>#{7gIz|(!ro5_b#uf=bXlCH)AsuV5=YcSeeK`Y$+0*hd z^h5ham8e?{y<-8i7*3gVV0b|_ViV3;LmcE_`=l7ccUN#@&ag+ut4}fDlwzv7z9Z~@ zx_#bksz;96d%p3eO3Gj=@oh?6KzzHTHq-TjW)}PNmJjb1HQe*3_?OE-mprYK>(1L= z9a}dm!0O$%%mr5GeBD`XnXoJw<$+82!nYjS;WXGnSz|FCAw4c;1%z2ybQY#a39g#5 zFoNbJjF+uRa+O$G=X$ff_vzP_{`rYyEi8p*mrwa$uXSl4Ek9XX6l=1W0?wSv=x}OK zr1FU%s!FW7M@L7_r>Br735(6A3Z>D^xmtz5V={D{hxFtf#M2JH)xMt zeqI^;9TE{GE-`5}WxS+5q!W&dc4sw+d9<0{lN@iIc4r#a&E7A^7bF+1HrnzC4PF{J z@pR-{B!?v+Dz!^UVhY7c0Rb3vma1rTpJPU=xn?AgzlvV&O#33StF6QjCWl%n22?BZ zFvkT!6g1Ux%Q{r-6j)fdagLZ;_5Y~Y<7(d9R%T46=E{_ZHmr%5It3Y3af{A0omKRf zd^^iar+=?;NqwsVWt>5-wR||!Dlket#ec+qk^^q68tS5eJu>qzNG!vdCjq`$m%yxaH z*xTtmS|k`@fBOl)s6x;$fXdTSENZcmz@CG{i%`I}t@ zT0shZvgg97>Qe$(M|eRF%T{}o%7tsaR6^C;YsK8jH`Llj2^Jnf@$jlbz!itG@P0g% zxyy(kP`8+@WXm|i@Ki;@MQhdlDA3i!oe^?=h#@OuP~7V#@8H!(fXplEI|8A_syj($ z%gZip>2b2(u(c@@uUz*{OCZ^DMb=#MfHWa=IQ@GAx=X8Ncdtx38*;r#G*@fwI$nO% zyWWAfry3cS8hdK_MEg{XK*V8AHA1K5Z67s6ecgmtyHoS86jn}%Q4nT%%-jb5(U3K79mWKBS8J|TmP?mDvJ(KDyOW|2Y`m=qg z{lS*4ALbhz;!J+I-cUVsC;YOCVG916$`%KDV<(|pxQr=$dxVtNfNFGH>G=iINFo2| z$#P6gN#(+~{<(&x5Vq0t6Rc>vzFcQLQg$Ystyme>33$!^<_7Gk@WoIx6l}hwg;tAi z_XW5|>o_eXgo`n@L~C5icg{3pVaJ$lX|C(N=5F+Y)wEs415YqIw>oH<%D=q6P&dJC zm`XA69)(wgMO{lZ0zUk6%N>J8Dn8vPZ8y6Nc`)@Raw&82qkWy<8en$!P)S!yx&vNq zO6YeaIdN1(c})BGd@#mzyxxqR#6fK#kT5Pj`5r z$AD=xRtrdt3hwCV9mA&!rOz8L0e51tIZz>dK|%xTuj-it^N+man}*LdP)`f;&-8r>A#&jm+~6dh&Y$ zzb5ZKeswU=FRS1^i^JUlB&7wPG)?*>C@~2WnnzU#&mX6%0*vE%%#*pdf_pQTxD&5f zp^@xn?C&-GPqM6y5f9qtj_aHKCOM|~VJ+?I$V5i4S^7XjtLuZojuJA|>N%4~w7hzZk4KEw)u#KY^(RUU?z> zDq}|`1qYDVtztCTL#ZE@*5+m^Q9?l+kH1is@?m-PoSJ#fBGOIPO86Z`C^5ZNZ$LPO znJoEDaERqNF2Ms{^`mAD;f`T+q=|a!mBLbbyK}|*?0U&Ccb_ue;qQjQtJF?AIRj}) zw3a&|*a!oYu|@fuRNXifw+s)>Nb^l$v1KUnSb!rqU9SpMq=u^}nIhDzJEhu$o$7t5 zHX5muGVfhMcEP9CIb>P;vw@p3_VEOrhF8-Ixa!84GfI6r^l@&D(kCiaMQPA37UKxW zI+T4*>~x_J2UEsfPj}~(f@K+-X%}9)vF+uMFzAr2V>P%nOJre-sZry-GNXH~T_&?J zSU?1lU1PD-{GCK0WXV~C>b1E9Ry=e3G|Z6qyrS4vi414BC(O;D%a4{vSBAF5cU@&d z*l&0%pj9sf^$W5X!uMCX#LopERXj@Kc4{jIowjd=eNdQ@A!>6R0_0f1I*Zn1^_!+|$ z0R+N-R@S1m2>z_B^}GstD^vS!k0*iRHK*q2T2sTx0>#DQlJ*YQvWu|rS#=D? z1%c3hgUH+4n3!4qr^r>W_FApR5vdv$?!~fd&8>^-y^OQGQzJ$t z<%sgWZ2qKm?#J~}T@`S(Dlabf^BZ=<1nYJccw`;F1mNRwbIAjbT27Q@_F&;xY&1^6 zSIf#g6Sj~M!0R*Np$BVmM=R`Q!!(!>P4uu_>L)P2WPD&z0SSc+5|M*sPOu{gp5?S8mFyLB8QYb0~M%Pyn;re}B(i%ZXhMJXrEY*UiR_-i~8*f-IqCK#~`5mqU+R_Kc zpN3L95Byrt^(=TWgH3U2Hx|mtM1W~ z0Hrx*N8zUdv_-=(KWU?QTKFz?-z8l(Jc4$c*xMpSuXgHKG($d0t>5+xxS?;^Na}CCbC_oVr^ow4*6?P|FvtNkP+c8 zts>*5q+FK}WJiykM|YG6`1Cgt@)Muddn6_fhI(A6v5nFtmk(}>8=L5Qk}5LzbjKyq z%exQjDt#3yWtmO43Mh*hNaEkX-6Fr-l&^l*XEH|`(y@OUaqM&MbJe({a}oi*a6pn!phpU))Eh2ei0C0>Rg`WMpQxe$IMoxKA6 z$&tB$^i_J2kBt2N;_iUvC9|8G?IceuZ?E4-kAz+nE7UkGkIfi)iRr>gwVGWk2N zzq2s>W)wyK2c!RCX!v(Z|7mLgo{bSNoc=)xkN*Dv|GUfKuW*00Is8U@_yg^Km>z&< z+sj|);qSZ;zhQeB|Bocoe|JLsJIlZGL;L{;0YYMpXR*To{$d4r@k9I*+;pqIw| z=T-I6xc@zuziZt8!1zZlG8)gh{LeQ2dwssFr@uDx7bM`H>nZpJ>Yv`8|JK+4eWL!Z zqrag26YNU&53v8$-(LVRsQ#_={G-i3dvLx&zgS^@A3k8KALAqJNQqyb1zzf&`SWjX n&#&kE{Ex#249+4x+5!_x{yo%l{L51Y8p!hbvE{SH%eVgr6GjP5 delta 13365 zcma)?1yo!~`t}=l2<{MEg1fuByK8WFNFzZ4!O{?d1$PY=+@0X=?oM$1U}k4BJKyYo zx6bK4efoC&s_Lz}b>Hge$z21xSqH;cl7)c8000260FKfPsr-Csm0LsrK03b#*c=OSG&?-79KZ_ zOuWXHglE)*O13}eh}&)WVg1o9?T+uNWqJFGVfpw@VEO8&0C7yG?fZ0Yg((sTW`JZm zH@O8;Os6jzJOGC$23nY+4K~PGSy-r^SOF-6{GpkUT)8@sT+0|45nd<*7BD>$Wdwu! zcm}?M9N1ppOcAiU0!xlz8Mq2ohYUuKR-lOJ=ibl7QZ3#FO zC3O<#{_s^kX=l|x7UCOFKNi{u`}F>6ziRl-7R~A6lh1vDV3zHN($~Z=5E5W&kelT= zh*)a%y>0$o1VXbw5hg$oxOU5O>QHaTQdi&P2mh;+r|Gp>;RzD1K(i4lZ}i3!1<0xb zP!nUwZo18KQsBt7`(v8&gjD`#=nx?B#)Ae~_#)D=(XmM9{H#yPZ2@TvB<6kHApjFn zB9KKG`EguCS_v?AP%n_75y!^W(aeGf45&Tl6BA-do!#bs%p$+p7(<>kvt>jf$u*DN z&k*lIjPvH^);?sZ4^ZFIiyNu1&RfBHB03%&t;q2euv~BI&i0-9TJV6`Mh=7_foB_g zsxC;^^SW!55sZkV{(8x-dTuGp&1nZ#B^7e+uBIZ3~ra>QYEP*!X2OpP%l*kqo+!El&Ik2RPVG900AtmZlo2!9_(7}#sP!*AK>h*$` zB_E6~Ew6WReT%GW7@=0mly-h)bl}XV3z$` z{M5G{K$ZPPPhDzLXskTFurD&YG0F;d&=T3W1hFgDaCo--+OQ%<8C1Rov^;d-mm?v8 zFqa+aAnZu$8=9G;z3{ufH&e}^xU3DjzIejBcb=Auq?_b(CN2`FmS(NhE8T*3nJwXk z9dhICtR&iPB}3ciMHR?E*`@L!+|a^&(+V@*f;P+GV;O1HAKWhVnh0#*Q0$JgWk=8q zBTpt-cQ86J$B-D%LjEmClm{oq8(y!)7J`!P3;LkE$`2%mq<-=f?v1&;^Q96f-!mf^ za_D6Vt|YZvWLA2+>;|Z;rZeFTGFvq z?PwffDnefZvW1hOS$T#%*@!i<_ahHxuIvLoS-M;(j++$Z24XwrxW{*+dk!RWGL!3E zk%`FA`mlA6?+EbPhUp94>IMcm^7#}9G9oE%*wd=(ajxc(>mEpbLxqfcMV68b!78&( z=yQbVn{kaDo3ce7jajr7!u z2sBaWZ_ScR zJe=&z#);ua5RmrXLGJ_!c)4|W9_4g4P&dc)Xp_XCoZRmjOn0rB$XUuQTwUDwfF_`b zJIjEu3Aul#bZ)fZy46Fc-Zf$?ZTlMT6qmehyP1{iBQE&EP5cP)h{p*qzUj$~gS-JI zcE_!CT1D_1*HZj-q}!&j_D50;4Wc)p{AP=y)K`kvKwzc*BYKdkw|UQ=mzLo;e08?d z92VUdF-NZ@G(-8DnbnwrN{^B&5+4uQ_IUa_pGL;KoQ=rBJMkalR=mMiwn3%}ft(ruXa#?G&$)UGo+ix6dLn_`>!rqN*D z21c21$p2pcla<6GTw`{}?%4(5XswYx1|dB?QJ=E+L05NPT>-vsDroz_kRMHO^2|-h z@_yRpll`LXS&RW(PUjoTk#?qP6G~OBPaV$jN+g*TU6EX=8Lm1cdH;Lts?$)Acfr zRI___m}X0s1++OI!mBqzSH!x7+L{Z3D=KAa&XraB8~ob7cc_=fX(UZAEZdGs$Iec& zI!^;t&kvRA2-wUAF2v}eAClRaCl=dvN~Ij%J zaMC;|^-Y&Z4dj9x>P6KIB_(k=**;b;*c=>aTuO|AL$7`?JR|qz8`KdyLSo|I+9ia& zwHw0oYvdCrvCejkHmja;=Sk4!F!FOUJfZ;V`5^E!NJUC-2tH)&f5gBDX{FhU^+$gV z7X!14LPWucrU2CrFd{bN6O)56bi8iEArrb3rE?D371n{Qh6GQ~zz*m5HR#J9PDgv=F*Y)>G6R7 z%}*D&$v7VR+OS( z-%sY(kB0?o6gvWvWw&l6b6~cpS3J?c#xrigFYe;ODg~!T7qSJVxHYO`#&%$u7t=p0 zf5?2?OW{vqCm=kgIBt)wftM&hh`Pv^$;P`~cAyUJ(YT~6j=j z2i#h}R?XX6`Uq)bUs8M4E;I-nD{m`>M)c8-C&~7ewDk=27Ly`KpTwGOD!a`YCp$rkJ3% zzUXr=&9-$#Omn56No_m25d{OPt}sTRsu3KPP~q1+h3iAh^ep<8uXx|g54>bfR%h{a z5r*%%N*^e6X=)f4{s3}(*TCpImdvXQAXj8BAPHZgz6n_A<|shf#h()L6U~rWpbw%= z;Wfb!4bgF9H^9K)IqH-=OH77Ef2FyJw6--=&tRT;+!1cBS}Q>u)8cx>4tG( z5Agk}GP(5FwJlE1E>^mCyH^tZRM)0FVZkIBv>WxzFTgzvtBXt2jpmWzmkw_;&CgH&f$)t-I{vp|c` zhH9r5Ej(OFeqOK9JeIwD^?vs&?ot2b8l_WU8?54?YQlO;R4$Mn+Y>FJVd4u9e~L!@ z*>|giDvIIS^8&;Eq55~E&2(&d+~!ee*Mwzgn~YdGF3oT9KSY?F-0hC@17Gud#Z;mP zqvD$6T z2FcH0EV@XfhC5fi0h1ga#knri2}qUnc+SDPc-begUuPyin?)&H+cv^{SO6dt7XUy5 z-~deDIy=~zGb%YdSXkMbJ2P0jsH;H%APAvcHQhWB0AP?8U;w~xXRb;v!wOgyF%L$m zoBI4L7Dxbq?wJGq%uo>*7LynMt)7x%qQ>9rQK9fb^1ak^KOQzdfdT*)pU-Qrezomv z?&#p``bW$EMEHV!3&s0Fuv)YV&Urrn(LHwx^Qi{<$6i z@Iv|R!@u4TUMLQBjt=(b_O33B|B3J`h%bPUs@~p~XI}Daz;ksR(5Wph&VQ;|IgHx} z&xsJVA>}+NES&J%aS{js;H6nBdly$@TU!QaGmGCU=gxZnJ?0=?q*kzO5CJkjP_+=@ zKnI}*?#UCa8A4Ug9mGog#H#rapmJtg<-Ad}*X!Y04i58v>?)o*W~T8P6NvDJ($h7+ z`)h`yk)@r-=>2X9=GzbR`1}W#X1?UItsb$k?o5v?&A3i_nMgVH$s0trNP*+I+6X(f z8zIG^X^mZ)OVGn&!`|GmJw92w##NWn14}3ks54xwD^})DTUp7IlRusUC~pz|JvOqv z+h=kx0Kgn70D$`E6fwHGm^wQ=5B6W{>z`(Mh+G4P=Ow%&QR-E!&+FtB5&(ew3*qEu z^?$CCPHlcDQ3ih+@9q(GlvVk^gVOiqc1b z0bgdUc5E$Fln?+&uz&u8;TOo!*wWnA!PxBA?eY&(H_5N-gD&~`_z^SM9sRq|XInIu zN{$$(_tK3vw%shUXUxSdpVdC`R@M8|>tZRaJvDEuOgHzkFjZFa0ZL1Gfa-2T1ukW0 zD;c%5;qc5d2{&Tl#ys(B=1Gi@RhR>(WzH($ESQ_|7&$+%gQYCbJBrS~Q%8xOdUHo* z^?mlFR>=Gy2S1BG?RQ$+GLPNEiW)ARwD^U&OtF)ePVCcX6Ff|FqR51tlyG%51L4qo zA*M=dXq=X8S!Ou&*r)-fKp+r}rd>rZ-n>Q-htBipUD7ZNzy(l=bi1}{WK;CRq4QW* zM2r;`k!o$W($XYRZj(-Cqe|BBeJ!#}z_L+U1R{XSd^D}oSh;tt)jjMUSsA<`Eg1dC zrNIrM=na)7X$&#g(c#qRaSv??=8yhqKUsD*Dqc^t*KgOouU1U>MyCT!mS_mk9{yO? zl{wB|dvzUAe(jj{&0=MA>1YS(LM7|FV@sZcfj%-2_bWl9(Xt|PKD{=BL8uFNV`3}U z+a*=Mj0ZjN(|o6dJBH_E=MaCAIcStI3x~;r0kq9ZinHz@zpluVWEekkn|J(J+^RV4 z0@pdnXa*u-!vqen=;Yr}*7DA~yaoQCAXUyFjSR=eJ@5r zVMr+*_v68-5(Acnz&m-XU`Uc|yiggk=fDvf))y%+{Tytt;Lt8kZXDBBdla~!NafgR zCUWf-(q+ZPFCV%JiJX0v@nyq`;I5b4h%u9tpa%^%?+mypKRS}MNt0qcbLGS$OIVKx zUGyd~EFx>PYcrxUYjksVetaNeU9%@o@Ul}TTr7|ppsX5a#h|?c2=Ag(#6Cy=Bd_t8#tysltEP z*nFKDP8j&($C{(TIaIpP0TK~PGvU40$nlkx(Ky!4{mOJ!T6Bm5LllE#$InU-NcMm( z#%7|}Q~)ES)Yk+fS#HdiHZPB)Wa%r#!f7%egJ(flG3-e%S_r47FGoc=GzxKMHX&G~ ziC4z;7cnD4f^L6la#4ouUP11GB{TS^ZqD-#@{hoEC$1a7J>08TDkQQ<(Aln1@An-t z#Jc+)y!=T%_ho+^BRBf+F|egfVSKcjoP$&3&S-y%;aZQ8rpiXCUNqbb()6OBv(E`K z|Fxfja2h{m1Ah`S5O!7RI6HBCJQ&{h^X3_kOajz_&N?^_2D4L+>x@?WM=t0&2eVmp zRD})@3kMb@XW{{VHm}xL#NKX+Yh?Jij}Nl5RuQLlS;o0Ah*GUq^Ns1IhYiS{gBg4g z0+hiakJB6HO>NM-CYor`yX5@&-NN*tbkc!bsSpU7lbsARU=pg^6uQ3VwG_qMViAP> zW@y(Q=Uf^sTG%QfZEvXlbsdlarySTesEAVstQQ2$6$bQ`A7p_UW~DU@oLL1K?v}c7 zJecxFz=RVTI3rvY*2*@TPr4gTXJz<4RO@_rg%T%qyRWjv*)xZZjJLS{PK6+uVf*Y@ z_QR#`bgK&R)p+LDaxS<=mfb2HOvx^~;=RgN((J`BVipxdl@Pl_vJP)?DicP03ln{X6NN52*w$ z*EEi1-qE)1kGk?=&Gba=*O0YOgE!Iv2LbCCRi&bXFcb5n7WH~&ROO$H8h%^~>(j5( zBvxccp=v1J`{Bk@FwMAY>b}+H11}+78S{%Gd+Y+j-F}nXq9!I3t>V%CRG5<$61uqP zLn(<6@Vt=cv**jdtMlY9bP@x#*w6119W_fxysZ1*xwB`n&bk<5>e+P=E|mZH$+ql) z4U4`noZ4_@3o9Q%W3s`IP@G4?Kj(r2(ImubhH5cIJ8YELuYjQqOze3e1%cirM)ecC z1zZAiYt{X=!11d^zmX>t=t*bBCa4bFB*jv`S|8tKxZ#9W6>Lic=L+mFM@Em&FPGE= z5b&?2@7FRsDpxV*l4#pw@qIB9HUC&zc|ee?fRybx5pDuRVi9BLcIE-I;xGd6PM~iT z#gofdyf)z;`=tKK+7U*(IgM}`s@b1e9}7w@SWV^Q!HNFIY;FP;)9h| z2$MV&LD1!LUQN`l@&~Dt%R4Jd(Dy0tEQ6+T z&P`U3SagY0;H^lJ{4lgg=59Jhkp}S6Hx$L8o;Y@bsSoERd0WPryvS;XS#SAkN z(v6En?FVoa#E8_aP+fSv?~%|C-f5*kfYfYox!LczVqN!*3@Zn~@hd-({U=g~}mK;8vl&U_=9Q>=qD39oS;VKn|ice}3(LGPW z;PO!L0~ngwbv>W-9H2P;S(&s)M+Q9Z|o4<;p`7+@Fb{wsFwv-j*(&at=^F5&J5j?|}Ld25A| zws9u9Ud6iYgPFFnpnkofHs+Cdzv-L!AXI^DZfZ$*Gm z+U>h>qU3He%<=HiQj0{zj0UpK5~Z8^e$BYNA0m6`m=JKWmbgg?j{QGOBDbiK_N)%Z zD7Y3Hm659H4X%&AJ?Z*+Kgq&CMu8VkI7*8bSGUOU(Pk*(VO>?9SE>TL_drvp@=5-DWorrMCmj0eJJ0^Al01PN{H!Ntn@db>6O zNVShl@4i#HbK*0}QVozgVrE}S;=Web1;{f8k7>y9XqUnmr~&lCUq{5wFfwC9TCeZt zZYW^$)QlTE!MW~~$1qC^r4qQ^pG*nTn>u-f=Ezi}E<%2)ksC+qGc<%aK_a z36r#=s4Bi}C~JJ;m!pGdyzqu4&8I%mqBX60FtQ>jl+P${k~F=yVH|GSr6 z3M)8tXj({RsN1%cCtdRmWeW_#j(x2K*;2P) zD+kU%&xX^3@7YZpBAp5P8;6Aa_Q&AHT@_9&Nl~!7wd^ojWGezxm+0lA0>JsuJ9v12 z8;r!U(A$R{YKJ;uX01o-MXlsHHS0t5FRjbm<^%?rSR0YhOEo?O#vG3~390=OD#e5j zfi!XR3!^bWdLC=~rww&SpiWof(-Sy0rC#kW%N(M%OzA%21dq+KXG@vTS&5el=@y3o;t9e^2<1y_??O#+vFu1x1!YzKeCxv#NQ4O>R85Swda8QS%V z9lP8@kDLBgh{aI9<5HfCn;?u?%;i1;^QV-8>n%ZdV&Ikh6Z-XWTCe-n2FG+rE!BV@ zbRG#5^B9k+rdfCe$vXPX7wu_z50bk0p$t06?RaICR}MfGR38@rQkHo{Fgk;_gWS)4 zYy|QO6?d#FdIMweNe|B8)!_1^fMU!uq+$rrS_cx*GF3=^^uSVK!Ca$%mg2Qy_DG%Ncs@Le( zg>Nt=7TyCLhG)?ACB11ugU5K+{QSuk)kOt5@5&RK-Ni2I=sqJTJXpY!DJ*ebtAwHpqkCl||7y?DDjVDj2xp(V2ajYLJN zaC}nlsg)<;APw`BAUChC)6Ln&NzdpeN=u^vK_o+HXh&Mqo~=?qOB7P;V!hI-75pRG zbXH&FO*>Uz6P*^8E3T2KCi^PRHIAftIsXg?bp}H{{9)bo6yrxr*yCouGSuQELe4@L zrA0BIOUWp|{E6aXE2tZZ&uXDHXN%lzaBwm7vshZWqtD>+C>fbnN&|2>jr;qfHPPPX z=H@`hI=Wv6iA*O)@z{2xq{zh>l)qgT1i`)>5(Lc5#sbg#T!y-KG}+fGUx#d~IY8W* ztd0i}ZweW0Tv8TYR!UC}S8sL`^hrb}-gMFeLn^T??`+Lg40y9;sq-mz4b4vz=LvXu zVV1NX*hKdcykHE+E}z)6h{A@Mkdvp+bBYHW7Wa|-*4(qyzoEOJuT+FF*+Oa%SZ6E6 zt!k;Cx6);23(4o6VhH*^t@zY{AHnM_?g5ms()y#x*^I$lrMWvX-WQa5??`1@?VYnT zV%0FvZsE%)if?lC91DzR*=7dqwvUNVEsg4{+Ipi)&o~6hrJsLj!n0icqBE5TiW9R0 zQwQCPQKQ|(Gcm8T(s(TqhYAPRVazYngE+*AUa^-iRc@;v@^-(QLOcf6j&&(Tq`H>dSoBBZG;&yvw}!!hQB z42?c)K1bXakjSIa^)9{{o|?@L!`#(~!OZemC0LHD6UMa-mR$PS<9n1QT^2{>cp@GY z=?Hz%mm_dHkaGd6$0K81pN9nM7>(#Wd}Zq(&;dP;%>yUMNH%hA?6^e%jT)n(G5H)Z z4WCFOPOKoJmbQVee&gMGlb1%e#EH^;o|H3`?$-Awran2^X?weB0%HbWSNG?u@Z^Y; zvfJq?D!X=Rn|}GES!)vf+?m5>6Jd@Xcfv_#3ggI{Y>~0G*J|sIM&b&7TLUjY zt}R&I7G0ziaW@l!>owx)%3dB+U*Ux>L5idIh^*;^GN6RZ=PIct7z4Z>1F}8Q)bktw=XRFH`)^{$^#QHPs%T~Ttp#Hi zc$hKc?bnxbq#YAiSSgHq1rW3$9>ZuozPqL$&MdTdV-qaHrc%@x& z29S%7G{Q97&JMsyXV_61?8HEw4{m9;=oWmkFU+&dP>=ElmLw3CHAk^T9?%%3>CO zFU!X&)BAk46*{TtSbAfilY>S?yMO>kx&v%nPlq6{PSbUq{kuW3c@>B0vBm|y{)G!I zwn7}fA~nP}?d}~7L$==9;?Ajk3b$oMLZ`hr+-Lg-<0%?$%33mT_;1JczE9 z0$7SV8}dVVRx~~W&6k)%@`~1X7fxIxhsq&r-m>N2S^P9B0V5SVOyQU#rpF31#H%e$ zl9Olk2-q`|oy>Ja6U|vN?=X#!r)tg2*j0`X2}&2PvuvBuu>Vn7%B2S(F-bD&++^B3 z3T9oFV$oN2k~Po>q#w&J%Mu~dZzMAC&o{}tNtY|$K}PVv>!`EmbVH||a9l%wJ^Ry9 zz47x6wVqj=jZYxxt&9+G9Ir6_Vw9}9!91-+=Wu|A3w!VL(@YG0Jcseq*A=}Kh0Ysy z_`F;u^)a5_#vN2HLOjYE{_6|fpJ%z!g*y8sUuA0?sH(}`QTxTr zhYsgI@EUL!uTc&q!su4^;2Y>TMXE@WudQcX7c11zT@JJ_v+Z}o zbS>W~g$_~u6$?!svERVdq+4TS-CP8^ZRoo=RG;EyVGAp_1g=te5>e4~<+nK(vR^V< zUUw!VV*en#Kt}fk7D-A^dEHK%s}WgT+e`JT&)C|m@6YRX;%<3)2KCgMC^s;oCSfD~ z?4?Y!grYZHoR8QMKNN!tiy%C*U1GO+H;(Ax^l@<#*-nZp`UJnwuOZH&>*|w%JfD+E zH6IqScKk}k`cn|Y0|T5Q?On5KoL;CCTMjniRhOo?q%VaYQ0VLak)c@yt&nlp(*618 zQ3%~isvkDgTP8;P^Fgi`u&5{M#v-9-WaWkf^+}o%EsU*7@@1u{5nOI$6iR+AJ`V3X zEtwQmOS)YVa(Q;lOZ`%wG=Sifve0;39gXrtCF<_eg70wRhH2NIhh?*#aq+~yvD%bKUJo`CyXG9S602tG{#xpqF-xmZmIjfv7w z#f7SE1ZxvBX|m$X!5%mSgImm}?=CmN_4?E4%@R>q5WAL-jG`|M3=Qygufe4ZYEx>^ zjAV^lDD&$a(j}RieS&whq*TGC-1|;|lh0(`#=8;-1Jv5j3doAyxocRwQqx1F0C{r9 z6E4qZG1UJ6OX=?^HD3F9g4&$+VSoa;O|Qj-s2Bjas}a4ZzH}WADX9D8OFVQ(wryjAuicD1hgXbFQG6vAcA{VqrNTJbvz^ySjNhpxWxPSRT<$eP+Y z)C_ZkB_N*T=xFT?{MXB_8hhjCJ^s+g{!(kSiD4(zPwgrXx?r#*8Ckp&BNaEs+9G?( zvzmA78a(Z19IG>RS4TVCQV>=u`5?COg0dT`X`^~jAp~4Yt7KPFAPJUtVqm0~IHNy! z5XVC)^3b{oUrQ@N={xSBK|oRaT{G03MiLBa01)Psqn9p8EbiUWiH)^Zn3z8v&5y&7TC z2tb|y%(cS6ZaThZ)Pg{3eo)ai*PC}53~;eLw5fioO5^fN`!H18H|zHrc$WR8x}m!V zh{Y`QIKq`d=pG!VG6EN5x^#F6(oUFzGJD1-G!fT=U)i0^4kxBI4l2V_+{~+6vSBdN zSP4@FM*(xWfi>29i{Bg_gzUY#cV${koc7N(;I2ef$Ec9FY z-4i%F-@P7j#K*RzZ%(m{n`WK61Yl$z9zQc-I*KIyxK9^oD}2O$k*I#x{}2?Pb)CNo zfH1#wo&Ti5{Svrd6ja6bypY0Y_48RB1>ir6f1VBmzl(qWq?u-^l|qXA?pS?Mw$f;< zoZ+A4zk0ZTQ$X#^?HruF{*a{pNgIP;#DEaKmWr0rS{YLodT!nKc{rHAy8ahQ%G1sE zw}E7BzxunJSc$770||Vw&VoT!BHcX8V`I=S$`$}1FRms`FRdWK_=l9rU}q6ODIZ-S z^$M`k(9+(Js0;~3l?VYI4o@29yBIT!l@wzCYGb+#wCGnEYsR`HRWHJ?rjA``=+8xZ z5sGOHu5`+tD`1&5IvP4Ujf0VW`STt<^i&G6PZ5ZdMg<$h6TD$l93FA1y;U&!b9Mdr zXW6L?%7q!k0z$gVOy0KvIN^9-VDvlECoz5F^(&+53F3a#y06ug=y!olxz>}%z)Bbz z38vfkPq0Ax-VtlUx>JcnxFYc!$uY0>(A%QcR}RiT^25CAs8e&ffh67E!?%lQZpfI( z4b*@+hEyS%w`Su7c*oDjGMjmGfC*?e{lJ*zNswy>;JQaP}y>qmS%Y9bu+CprCHw2#fRg zx&R^0q=co>Rz2A2UBHu87n@c{EY$=>@11}U(5Wl61m{{Us0b~`_ry{8O7Wd9LC*exWn%J;o!Mtye&fq_-aS7^P#1)`6>z$SyBpPk zAKT$K>53XY>|byY%K4$q{A_z)u5Zgw%U6K-#Wr!yjgr;f61$OS)c{o;V$TEMl2e1F zDk&Z+lw{Xwy39j>XP`*KzBVICH&!;o)9MT5hBA7J6srk{l6k*OiXlFnpXB^1Kc*{A zmvE5Y5CxVet5~x?c-oD_wgWLWy|7XSC{^~Ojo!;%T1)_3Z9@6Hj-*-s<3ftyt?lUZN7QIpN?9#{tX6>Ejtdip$eI41AX15QLad$?V7+c2g#LH!ln zw*)*8L6z8(xY<$@aLyg4gDFcQ%xo#m4~n9%=#)?Cz!Il6B>`y-d0|T#DH&dw+=xYo zj$Rj^bF=hx9Jo@VH)=khJiI3Vb&9zx46%HjiJ}*4KYv|EuZa zck1uE{tNU4@<(~GU;JKP0S<)=NuHrE9uS%TW&-*5Q2xyZ@*D8?DcUCio!H_5|C1-= z&jCM=_n(|0FQnf=*K~mY#V7Jt;LBKlH(@+a=N~SNU&IlHKO*=)cryOZ{kt>c7uJ;H zPwbyQ4dAnp=pP&UE>#Yj`vUK|7za&EBqfl9KY!K{D0E_^7#ChLFFGD9lxXh zl}7wS7V$!Ud8{7_v+MpwmU?kk{pY0O*JApIwBk3`?`yzW7v$kU`1@k|haBUtBYv6t zzvmb)q~AeyMt=_Yzh)eNrT&(80RNVF{K7Vw{)zod9RH6r|ezn%msAoND4ps>>NV2efjeL0k!c{CIA2c From bddafc48dd2a7a260c13b7eae575cec436eaaf14 Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Tue, 27 Sep 2016 01:03:24 +0300 Subject: [PATCH 027/102] Bug 1305309, backout Bug 1214805, r=backout --HG-- extra : rebase_source : d86f67ef53b26027d739725829a2ee736d71221e --- dom/base/nsIDocument.h | 14 -------------- dom/base/nsObjectLoadingContent.cpp | 8 ++------ layout/base/nsDocumentViewer.cpp | 28 ++++++---------------------- layout/printing/nsPrintEngine.cpp | 20 -------------------- layout/printing/nsPrintEngine.h | 2 -- layout/printing/nsPrintObject.cpp | 5 ----- layout/printing/nsPrintObject.h | 3 --- 7 files changed, 8 insertions(+), 72 deletions(-) diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h index 0a5f750862f7..7f418d623f9b 100644 --- a/dom/base/nsIDocument.h +++ b/dom/base/nsIDocument.h @@ -2768,16 +2768,6 @@ public: return mHasScrollLinkedEffect; } - bool MayHavePluginFramesForPrinting() - { - return mMayHavePluginFramesForPrinting; - } - - void SetMayHavePluginFramesForPrinting() - { - mMayHavePluginFramesForPrinting = true; - } - protected: bool GetUseCounter(mozilla::UseCounter aUseCounter) { @@ -3074,10 +3064,6 @@ protected: // True is document has ever been in a foreground window. bool mEverInForeground : 1; - // True if this document is a static clone for printing and may - // have elements referring to plugins in the original document. - bool mMayHavePluginFramesForPrinting : 1; - enum Type { eUnknown, // should never be used eHTML, diff --git a/dom/base/nsObjectLoadingContent.cpp b/dom/base/nsObjectLoadingContent.cpp index 9456f89c3ec1..99ca67e375b1 100644 --- a/dom/base/nsObjectLoadingContent.cpp +++ b/dom/base/nsObjectLoadingContent.cpp @@ -2907,13 +2907,9 @@ nsObjectLoadingContent::CreateStaticClone(nsObjectLoadingContent* aDest) const aDest->mPrintFrame = const_cast(this)->GetExistingFrame(); } - nsCOMPtr content = - do_QueryInterface(static_cast(aDest)); - if (aDest->mPrintFrame) { - content->OwnerDoc()->SetMayHavePluginFramesForPrinting(); - } - if (mFrameLoader) { + nsCOMPtr content = + do_QueryInterface(static_cast(aDest)); nsFrameLoader* fl = nsFrameLoader::Create(content->AsElement(), false); if (fl) { aDest->mFrameLoader = fl; diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index 145ebd69b366..e894eda303f2 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -3762,7 +3762,9 @@ nsDocumentViewer::Print(nsIPrintSettings* aPrintSettings, return rv; } } - + if (mPrintEngine->HasPrintCallbackCanvas()) { + mBeforeAndAfterPrint = beforeAndAfterPrint; + } dom::Element* root = mDocument->GetRootElement(); if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdisallowselectionprint)) { mPrintEngine->SetDisallowSelectionPrint(true); @@ -3770,18 +3772,7 @@ nsDocumentViewer::Print(nsIPrintSettings* aPrintSettings, rv = mPrintEngine->Print(aPrintSettings, aWebProgressListener); if (NS_FAILED(rv)) { OnDonePrinting(); - } else if (GetIsPrinting()) { - if (mPrintEngine->HasPrintCallbackCanvas() || - mPrintEngine->MayHavePluginFrames()) { - mBeforeAndAfterPrint = beforeAndAfterPrint; - } else { - // Since printing cloned the document and doesn't need plugin or canvas data - // from the original document, we can clear the print flag in the docshell - // tree early, before afterprint is dispatched. - SetIsPrinting(false); - } } - return rv; } @@ -3846,7 +3837,9 @@ nsDocumentViewer::PrintPreview(nsIPrintSettings* aPrintSettings, return rv; } } - + if (mPrintEngine->HasPrintCallbackCanvas()) { + mBeforeAndAfterPrint = beforeAndAfterPrint; + } dom::Element* root = doc->GetRootElement(); if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::mozdisallowselectionprint)) { PR_PL(("PrintPreview: found mozdisallowselectionprint")); @@ -3856,16 +3849,7 @@ nsDocumentViewer::PrintPreview(nsIPrintSettings* aPrintSettings, mPrintPreviewZoomed = false; if (NS_FAILED(rv)) { OnDonePrinting(); - } else if (GetIsPrintPreview() && - (mPrintEngine->HasPrintCallbackCanvas() || - mPrintEngine->MayHavePluginFrames())) { - mBeforeAndAfterPrint = beforeAndAfterPrint; } - - // Unlike in printing case we don't explicitly call SetIsPrintPreview(false); - // here, since this ContentViewer is for the cloned document, not for the - // original document. - return rv; #else return NS_ERROR_FAILURE; diff --git a/layout/printing/nsPrintEngine.cpp b/layout/printing/nsPrintEngine.cpp index 739e7d2be32b..61c534ce5931 100644 --- a/layout/printing/nsPrintEngine.cpp +++ b/layout/printing/nsPrintEngine.cpp @@ -3560,26 +3560,6 @@ nsPrintEngine::FirePrintCompletionEvent() NS_WARNING("failed to dispatch print completion event"); } -bool -nsPrintEngine::MayHavePluginFrames() -{ - nsPrintData* prt = mPrt; - if (!mPrt) { - prt = mPrtPreview; - if (!prt) { - prt = mOldPrtPreview; - } - } - if (prt) { - for (uint32_t i = 0; i < prt->mPrintDocList.Length(); ++i) { - if (prt->mPrintDocList[i]->MayHavePluginFrames()) { - return true; - } - } - } - return false; -} - //--------------------------------------------------------------- //--------------------------------------------------------------- //-- Debug helper routines diff --git a/layout/printing/nsPrintEngine.h b/layout/printing/nsPrintEngine.h index 153e6de286a1..6457e306574d 100644 --- a/layout/printing/nsPrintEngine.h +++ b/layout/printing/nsPrintEngine.h @@ -203,8 +203,6 @@ public: mDisallowSelectionPrint = aDisallowSelectionPrint; } - bool MayHavePluginFrames(); - protected: ~nsPrintEngine(); diff --git a/layout/printing/nsPrintObject.cpp b/layout/printing/nsPrintObject.cpp index fd4377886b44..c1caf762f707 100644 --- a/layout/printing/nsPrintObject.cpp +++ b/layout/printing/nsPrintObject.cpp @@ -111,8 +111,3 @@ nsPrintObject::DestroyPresentation() mViewManager = nullptr; } -bool -nsPrintObject::MayHavePluginFrames() -{ - return mDocument && mDocument->MayHavePluginFramesForPrinting(); -} diff --git a/layout/printing/nsPrintObject.h b/layout/printing/nsPrintObject.h index 207d5bb05c88..5103224f049d 100644 --- a/layout/printing/nsPrintObject.h +++ b/layout/printing/nsPrintObject.h @@ -36,9 +36,6 @@ public: bool aPrintPreview); bool IsPrintable() { return !mDontPrint; } - - bool MayHavePluginFrames(); - void DestroyPresentation(); // Data Members From b2c4616ac5c0129181e11a9da21fa37d301d8425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A3o=20Gottwald?= Date: Tue, 27 Sep 2016 13:39:21 +0200 Subject: [PATCH 028/102] Bug 1304363 followup, fixing typo --HG-- extra : rebase_source : 23835aa735d7ee4fbed6d4c6c0404db8f6fcc9b4 --- browser/themes/shared/identity-block/icons.inc.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/themes/shared/identity-block/icons.inc.css b/browser/themes/shared/identity-block/icons.inc.css index 9146683abf5f..6cf300061527 100644 --- a/browser/themes/shared/identity-block/icons.inc.css +++ b/browser/themes/shared/identity-block/icons.inc.css @@ -19,7 +19,7 @@ @selectorPrefix@#identity-box.grantedPermissions:hover > #identity-icon:not(.no-hover)@selectorSuffix@, @selectorPrefix@#identity-box.grantedPermissions[open=true] > #identity-icon@selectorSuffix@ { - list-style-image: url(url(chrome://browser/skin/identity-icon.svg#notice-hover@iconVariant@)); + list-style-image: url(chrome://browser/skin/identity-icon.svg#notice-hover@iconVariant@); } @selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.chromeUI > #identity-icon@selectorSuffix@ { From 8d7cb8d79e8820cedcd86fa2eeed2614f7989f54 Mon Sep 17 00:00:00 2001 From: Sebastian Hengst Date: Tue, 27 Sep 2016 13:49:30 +0200 Subject: [PATCH 029/102] Backed out changeset 4465b8d521ee (bug 1286911) for asserting !strBufLen (strBufLen not reset after previous use!), at nsHtml5Tokenizer.h:173. r=backout on a CLOSED TREE --- parser/html/javasrc/HtmlAttributes.java | 2 +- parser/html/javasrc/Tokenizer.java | 183 ++++++------------ parser/html/nsHtml5Tokenizer.cpp | 140 ++++++-------- parser/html/nsHtml5Tokenizer.h | 41 ++-- parser/html/nsHtml5TreeBuilderCppSupplement.h | 4 +- 5 files changed, 131 insertions(+), 239 deletions(-) diff --git a/parser/html/javasrc/HtmlAttributes.java b/parser/html/javasrc/HtmlAttributes.java index 0ec25f96f0ae..029703c19fa7 100644 --- a/parser/html/javasrc/HtmlAttributes.java +++ b/parser/html/javasrc/HtmlAttributes.java @@ -62,7 +62,7 @@ public final class HtmlAttributes implements Attributes { private @Auto AttributeName[] names; private @Auto String[] values; // XXX perhaps make this @NoLength? - + // CPPONLY: private @Auto int[] lines; // XXX perhaps make this @NoLength? // [NOCPP[ diff --git a/parser/html/javasrc/Tokenizer.java b/parser/html/javasrc/Tokenizer.java index 7e529035d846..14ad0c0722ab 100644 --- a/parser/html/javasrc/Tokenizer.java +++ b/parser/html/javasrc/Tokenizer.java @@ -817,34 +817,30 @@ public class Tokenizer implements Locator { } @Inline private void appendCharRefBuf(char c) { - // CPPONLY: assert charRefBufLen < charRefBuf.length: - // CPPONLY: "RELEASE: Attempted to overrun charRefBuf!"; charRefBuf[charRefBufLen++] = c; } + @Inline private void clearCharRefBufAndAppend(char c) { + charRefBuf[0] = c; + charRefBufLen = 1; + } + private void emitOrAppendCharRefBuf(int returnState) throws SAXException { if ((returnState & DATA_AND_RCDATA_MASK) != 0) { appendCharRefBufToStrBuf(); } else { if (charRefBufLen > 0) { tokenHandler.characters(charRefBuf, 0, charRefBufLen); - charRefBufLen = 0; } } } - @Inline private void clearStrBufAfterUse() { - strBufLen = 0; + @Inline private void clearStrBufAndAppend(char c) { + strBuf[0] = c; + strBufLen = 1; } - @Inline private void clearStrBufBeforeUse() { - assert strBufLen == 0: "strBufLen not reset after previous use!"; - strBufLen = 0; // no-op in the absence of bugs - } - - @Inline private void clearStrBufAfterOneHyphen() { - assert strBufLen == 1: "strBufLen length not one!"; - assert strBuf[0] == '-': "strBuf does not start with a hyphen!"; + @Inline private void clearStrBuf() { strBufLen = 0; } @@ -854,13 +850,7 @@ public class Tokenizer implements Locator { * @param c * the UTF-16 code unit to append */ - @Inline private void appendStrBuf(char c) { - // CPPONLY: assert strBufLen < strBuf.length: "Previous buffer length insufficient."; - // CPPONLY: if (strBufLen == strBuf.length) { - // CPPONLY: if (!EnsureBufferSpace(1)) { - // CPPONLY: assert false: "RELEASE: Unable to recover from buffer reallocation failure"; - // CPPONLY: } // TODO: Add telemetry when outer if fires but inner does not - // CPPONLY: } + private void appendStrBuf(char c) { strBuf[strBufLen++] = c; } @@ -873,11 +863,9 @@ public class Tokenizer implements Locator { * @return the buffer as a string */ protected String strBufToString() { - String str = Portability.newStringFromBuffer(strBuf, 0, strBufLen + return Portability.newStringFromBuffer(strBuf, 0, strBufLen // CPPONLY: , tokenHandler ); - clearStrBufAfterUse(); - return str; } /** @@ -889,7 +877,6 @@ public class Tokenizer implements Locator { private void strBufToDoctypeName() { doctypeName = Portability.newLocalNameFromBuffer(strBuf, 0, strBufLen, interner); - clearStrBufAfterUse(); } /** @@ -901,7 +888,6 @@ public class Tokenizer implements Locator { private void emitStrBuf() throws SAXException { if (strBufLen > 0) { tokenHandler.characters(strBuf, 0, strBufLen); - clearStrBufAfterUse(); } } @@ -948,8 +934,6 @@ public class Tokenizer implements Locator { switch (commentPolicy) { case ALTER_INFOSET: strBufLen--; - // WARNING!!! This expands the worst case of the buffer length - // given the length of input! appendStrBuf(' '); appendStrBuf('-'); // FALLTHROUGH @@ -967,15 +951,14 @@ public class Tokenizer implements Locator { } private void appendStrBuf(@NoLength char[] buffer, int offset, int length) { - int newLen = strBufLen + length; - // CPPONLY: assert newLen <= strBuf.length: "Previous buffer length insufficient."; - // CPPONLY: if (strBuf.length < newLen) { - // CPPONLY: if (!EnsureBufferSpace(length)) { - // CPPONLY: assert false: "RELEASE: Unable to recover from buffer reallocation failure"; - // CPPONLY: } // TODO: Add telemetry when outer if fires but inner does not - // CPPONLY: } + int reqLen = strBufLen + length; + if (strBuf.length < reqLen) { + char[] newBuf = new char[reqLen + (reqLen >> 1)]; + System.arraycopy(strBuf, 0, newBuf, 0, strBuf.length); + strBuf = newBuf; + } System.arraycopy(buffer, offset, strBuf, strBufLen, length); - strBufLen = newLen; + strBufLen = reqLen; } /** @@ -983,7 +966,6 @@ public class Tokenizer implements Locator { */ @Inline private void appendCharRefBufToStrBuf() { appendStrBuf(charRefBuf, 0, charRefBufLen); - charRefBufLen = 0; } /** @@ -1004,7 +986,6 @@ public class Tokenizer implements Locator { // [NOCPP[ } // ]NOCPP] - clearStrBufAfterUse(); cstart = pos + 1; } @@ -1092,7 +1073,6 @@ public class Tokenizer implements Locator { private void strBufToElementNameString() { tagName = ElementName.elementNameByBuffer(strBuf, 0, strBufLen, interner); - clearStrBufAfterUse(); } private int emitCurrentTagToken(boolean selfClosing, int pos) @@ -1144,7 +1124,6 @@ public class Tokenizer implements Locator { , namePolicy != XmlViolationPolicy.ALLOW // ]NOCPP] , interner); - clearStrBufAfterUse(); if (attributes == null) { attributes = new HtmlAttributes(mappingLangToXmlLang); @@ -1211,8 +1190,6 @@ public class Tokenizer implements Locator { // ]NOCPP] attributeName = null; // attributeName has been adopted by the // |attributes| object - } else { - clearStrBufAfterUse(); } } @@ -1361,14 +1338,6 @@ public class Tokenizer implements Locator { // unifying the tokenizer and tree builder buffers in the future. int worstCase = strBufLen + inputLength + charRefBufLen + 2; tokenHandler.ensureBufferSpace(worstCase); - if (commentPolicy == XmlViolationPolicy.ALTER_INFOSET) { - // When altering infoset, if the comment contents are consecutive - // hyphens, each hyphen generates a space, too. These buffer - // contents never get emitted as characters() to the tokenHandler, - // which is why this calculation happens after the call to - // ensureBufferSpace on tokenHandler. - worstCase *= 2; - } if (strBuf == null) { // Add an arbitrary small value to avoid immediate reallocation // once there are a few characters in the buffer. @@ -1477,8 +1446,7 @@ public class Tokenizer implements Locator { * reference in data state. */ flushChars(buf, pos); - assert charRefBufLen == 0: "charRefBufLen not reset after previous use!"; - appendCharRefBuf(c); + clearCharRefBufAndAppend(c); setAdditionalAndRememberAmpersandLocation('\u0000'); returnState = state; state = transition(state, Tokenizer.CONSUME_CHARACTER_REFERENCE, reconsume, pos); @@ -1538,8 +1506,7 @@ public class Tokenizer implements Locator { * input character (add 0x0020 to the character's * code point), */ - clearStrBufBeforeUse(); - appendStrBuf((char) (c + 0x20)); + clearStrBufAndAppend((char) (c + 0x20)); /* then switch to the tag name state. */ state = transition(state, Tokenizer.TAG_NAME, reconsume, pos); /* @@ -1558,8 +1525,7 @@ public class Tokenizer implements Locator { /* * set its tag name to the input character, */ - clearStrBufBeforeUse(); - appendStrBuf(c); + clearStrBufAndAppend(c); /* then switch to the tag name state. */ state = transition(state, Tokenizer.TAG_NAME, reconsume, pos); /* @@ -1599,8 +1565,7 @@ public class Tokenizer implements Locator { /* * Switch to the bogus comment state. */ - clearStrBufBeforeUse(); - appendStrBuf(c); + clearStrBufAndAppend(c); state = transition(state, Tokenizer.BOGUS_COMMENT, reconsume, pos); continue stateloop; case '>': @@ -1803,8 +1768,7 @@ public class Tokenizer implements Locator { * Set that attribute's name to the current * input character, */ - clearStrBufBeforeUse(); - appendStrBuf(c); + clearStrBufAndAppend(c); /* * and its value to the empty string. */ @@ -1950,7 +1914,7 @@ public class Tokenizer implements Locator { * attribute value (double-quoted) state. */ // CPPONLY: attributeLine = line; - clearStrBufBeforeUse(); + clearStrBuf(); state = transition(state, Tokenizer.ATTRIBUTE_VALUE_DOUBLE_QUOTED, reconsume, pos); break beforeattributevalueloop; // continue stateloop; @@ -1961,7 +1925,7 @@ public class Tokenizer implements Locator { * input character. */ // CPPONLY: attributeLine = line; - clearStrBufBeforeUse(); + clearStrBuf(); reconsume = true; state = transition(state, Tokenizer.ATTRIBUTE_VALUE_UNQUOTED, reconsume, pos); noteUnquotedAttributeValue(); @@ -1972,7 +1936,7 @@ public class Tokenizer implements Locator { * value (single-quoted) state. */ // CPPONLY: attributeLine = line; - clearStrBufBeforeUse(); + clearStrBuf(); state = transition(state, Tokenizer.ATTRIBUTE_VALUE_SINGLE_QUOTED, reconsume, pos); continue stateloop; case '>': @@ -2016,8 +1980,7 @@ public class Tokenizer implements Locator { * character to the current attribute's value. */ // CPPONLY: attributeLine = line; - clearStrBufBeforeUse(); - appendStrBuf(c); + clearStrBufAndAppend(c); /* * Switch to the attribute value (unquoted) * state. @@ -2060,8 +2023,7 @@ public class Tokenizer implements Locator { * additional allowed character being U+0022 * QUOTATION MARK ("). */ - assert charRefBufLen == 0: "charRefBufLen not reset after previous use!"; - appendCharRefBuf(c); + clearCharRefBufAndAppend(c); setAdditionalAndRememberAmpersandLocation('\"'); returnState = state; state = transition(state, Tokenizer.CONSUME_CHARACTER_REFERENCE, reconsume, pos); @@ -2230,8 +2192,7 @@ public class Tokenizer implements Locator { * additional allowed character being U+003E * GREATER-THAN SIGN (>) */ - assert charRefBufLen == 0: "charRefBufLen not reset after previous use!"; - appendCharRefBuf(c); + clearCharRefBufAndAppend(c); setAdditionalAndRememberAmpersandLocation('>'); returnState = state; state = transition(state, Tokenizer.CONSUME_CHARACTER_REFERENCE, reconsume, pos); @@ -2370,8 +2331,7 @@ public class Tokenizer implements Locator { * Set that attribute's name to the current * input character, */ - clearStrBufBeforeUse(); - appendStrBuf(c); + clearStrBufAndAppend(c); /* * and its value to the empty string. */ @@ -2417,22 +2377,19 @@ public class Tokenizer implements Locator { */ switch (c) { case '-': - clearStrBufBeforeUse(); - appendStrBuf(c); + clearStrBufAndAppend(c); state = transition(state, Tokenizer.MARKUP_DECLARATION_HYPHEN, reconsume, pos); break markupdeclarationopenloop; // continue stateloop; case 'd': case 'D': - clearStrBufBeforeUse(); - appendStrBuf(c); + clearStrBufAndAppend(c); index = 0; state = transition(state, Tokenizer.MARKUP_DECLARATION_OCTYPE, reconsume, pos); continue stateloop; case '[': if (tokenHandler.cdataSectionAllowed()) { - clearStrBufBeforeUse(); - appendStrBuf(c); + clearStrBufAndAppend(c); index = 0; state = transition(state, Tokenizer.CDATA_START, reconsume, pos); continue stateloop; @@ -2440,7 +2397,7 @@ public class Tokenizer implements Locator { // else fall through default: errBogusComment(); - clearStrBufBeforeUse(); + clearStrBuf(); reconsume = true; state = transition(state, Tokenizer.BOGUS_COMMENT, reconsume, pos); continue stateloop; @@ -2457,7 +2414,7 @@ public class Tokenizer implements Locator { case '\u0000': break stateloop; case '-': - clearStrBufAfterOneHyphen(); + clearStrBuf(); state = transition(state, Tokenizer.COMMENT_START, reconsume, pos); break markupdeclarationhyphenloop; // continue stateloop; @@ -2811,7 +2768,6 @@ public class Tokenizer implements Locator { index++; continue; } else { - clearStrBufAfterUse(); cstart = pos; // start coalescing reconsume = true; state = transition(state, Tokenizer.CDATA_SECTION, reconsume, pos); @@ -2925,8 +2881,7 @@ public class Tokenizer implements Locator { * + additional allowed character being U+0027 * APOSTROPHE ('). */ - assert charRefBufLen == 0: "charRefBufLen not reset after previous use!"; - appendCharRefBuf(c); + clearCharRefBufAndAppend(c); setAdditionalAndRememberAmpersandLocation('\''); returnState = state; state = transition(state, Tokenizer.CONSUME_CHARACTER_REFERENCE, reconsume, pos); @@ -3274,8 +3229,6 @@ public class Tokenizer implements Locator { charRefBufLen - charRefBufMark); } } - // charRefBufLen will be zeroed below! - // Check if we broke out early with c being the last // character that matched as opposed to being the // first one that didn't match. In the case of an @@ -3283,7 +3236,6 @@ public class Tokenizer implements Locator { // *after* the current character and the current // character shouldn't be reconsumed. boolean earlyBreak = (c == ';' && charRefBufMark == charRefBufLen); - charRefBufLen = 0; if ((returnState & DATA_AND_RCDATA_MASK) == 0) { cstart = earlyBreak ? pos + 1 : pos; } @@ -3422,8 +3374,6 @@ public class Tokenizer implements Locator { // WARNING FALLTHRU CASE TRANSITION: DON'T REORDER case HANDLE_NCR_VALUE: // WARNING previous state sets reconsume - // We are not going to emit the contents of charRefBuf. - charRefBufLen = 0; // XXX inline this case if the method size can take it handleNcrValue(returnState); state = transition(state, returnState, reconsume, pos); @@ -3570,8 +3520,7 @@ public class Tokenizer implements Locator { /* * Switch to the bogus comment state. */ - clearStrBufBeforeUse(); - appendStrBuf('\n'); + clearStrBufAndAppend('\n'); state = transition(state, Tokenizer.BOGUS_COMMENT, reconsume, pos); break stateloop; case '\n': @@ -3581,8 +3530,7 @@ public class Tokenizer implements Locator { /* * Switch to the bogus comment state. */ - clearStrBufBeforeUse(); - appendStrBuf(c); + clearStrBufAndAppend('\n'); state = transition(state, Tokenizer.BOGUS_COMMENT, reconsume, pos); continue stateloop; case '\u0000': @@ -3602,8 +3550,7 @@ public class Tokenizer implements Locator { /* * set its tag name to the input character, */ - clearStrBufBeforeUse(); - appendStrBuf(c); + clearStrBufAndAppend(c); /* * then switch to the tag name state. (Don't * emit the token yet; further details will be @@ -3617,8 +3564,7 @@ public class Tokenizer implements Locator { /* * Switch to the bogus comment state. */ - clearStrBufBeforeUse(); - appendStrBuf(c); + clearStrBufAndAppend(c); state = transition(state, Tokenizer.BOGUS_COMMENT, reconsume, pos); continue stateloop; } @@ -3641,8 +3587,7 @@ public class Tokenizer implements Locator { * reference in RCDATA state. */ flushChars(buf, pos); - assert charRefBufLen == 0: "charRefBufLen not reset after previous use!"; - appendCharRefBuf(c); + clearCharRefBufAndAppend(c); setAdditionalAndRememberAmpersandLocation('\u0000'); returnState = state; state = transition(state, Tokenizer.CONSUME_CHARACTER_REFERENCE, reconsume, pos); @@ -3727,7 +3672,7 @@ public class Tokenizer implements Locator { * data end tag open state. */ index = 0; - clearStrBufBeforeUse(); + clearStrBuf(); state = transition(state, Tokenizer.NON_DATA_END_TAG_NAME, reconsume, pos); break rawtextrcdatalessthansignloop; // FALL THRU continue stateloop; @@ -3756,7 +3701,7 @@ public class Tokenizer implements Locator { c = checkChar(buf, pos); /* * ASSERT! when entering this state, set index to 0 and - * call clearStrBufBeforeUse() assert (contentModelElement != + * call clearStrBuf() assert (contentModelElement != * null); Let's implement the above without lookahead. * strBuf is the 'temporary buffer'. */ @@ -3789,7 +3734,6 @@ public class Tokenizer implements Locator { switch (c) { case '\r': silentCarriageReturn(); - clearStrBufAfterUse(); // strBuf not used state = transition(state, Tokenizer.BEFORE_ATTRIBUTE_NAME, reconsume, pos); break stateloop; case '\n': @@ -3805,7 +3749,6 @@ public class Tokenizer implements Locator { * appropriate end tag token, then switch to * the before attribute name state. */ - clearStrBufAfterUse(); // strBuf not used state = transition(state, Tokenizer.BEFORE_ATTRIBUTE_NAME, reconsume, pos); continue stateloop; case '/': @@ -3815,7 +3758,6 @@ public class Tokenizer implements Locator { * then switch to the self-closing start tag * state. */ - clearStrBufAfterUse(); // strBuf not used state = transition(state, Tokenizer.SELF_CLOSING_START_TAG, reconsume, pos); continue stateloop; case '>': @@ -3825,7 +3767,6 @@ public class Tokenizer implements Locator { * end tag token, then emit the current tag * token and switch to the data state. */ - clearStrBufAfterUse(); // strBuf not used state = transition(state, emitCurrentTagToken(false, pos), reconsume, pos); if (shouldSuspend) { break stateloop; @@ -4000,7 +3941,7 @@ public class Tokenizer implements Locator { * data end tag open state. */ index = 0; - clearStrBufBeforeUse(); + clearStrBuf(); state = transition(state, Tokenizer.NON_DATA_END_TAG_NAME, reconsume, pos); continue stateloop; case '!': @@ -4258,7 +4199,7 @@ public class Tokenizer implements Locator { * data escaped end tag open state. */ index = 0; - clearStrBufBeforeUse(); + clearStrBuf(); returnState = Tokenizer.SCRIPT_DATA_ESCAPED; state = transition(state, Tokenizer.NON_DATA_END_TAG_NAME, reconsume, pos); continue stateloop; @@ -4740,8 +4681,7 @@ public class Tokenizer implements Locator { * Set the token's name name to the current * input character. */ - clearStrBufBeforeUse(); - appendStrBuf(c); + clearStrBufAndAppend(c); /* * Switch to the DOCTYPE name state. */ @@ -4962,7 +4902,7 @@ public class Tokenizer implements Locator { * Set the DOCTYPE token's public identifier to * the empty string (not missing), */ - clearStrBufBeforeUse(); + clearStrBuf(); /* * then switch to the DOCTYPE public identifier * (double-quoted) state. @@ -4978,7 +4918,7 @@ public class Tokenizer implements Locator { * Set the DOCTYPE token's public identifier to * the empty string (not missing), */ - clearStrBufBeforeUse(); + clearStrBuf(); /* * then switch to the DOCTYPE public identifier * (single-quoted) state. @@ -5049,7 +4989,7 @@ public class Tokenizer implements Locator { * token's public identifier to the empty string * (not missing), */ - clearStrBufBeforeUse(); + clearStrBuf(); /* * then switch to the DOCTYPE public identifier * (double-quoted) state. @@ -5063,7 +5003,7 @@ public class Tokenizer implements Locator { * public identifier to the empty string (not * missing), */ - clearStrBufBeforeUse(); + clearStrBuf(); /* * then switch to the DOCTYPE public identifier * (single-quoted) state. @@ -5214,7 +5154,7 @@ public class Tokenizer implements Locator { * Set the DOCTYPE token's system identifier to * the empty string (not missing), */ - clearStrBufBeforeUse(); + clearStrBuf(); /* * then switch to the DOCTYPE system identifier * (double-quoted) state. @@ -5230,7 +5170,7 @@ public class Tokenizer implements Locator { * Set the DOCTYPE token's system identifier to * the empty string (not missing), */ - clearStrBufBeforeUse(); + clearStrBuf(); /* * then switch to the DOCTYPE system identifier * (single-quoted) state. @@ -5295,7 +5235,7 @@ public class Tokenizer implements Locator { * token's system identifier to the empty string * (not missing), */ - clearStrBufBeforeUse(); + clearStrBuf(); /* * then switch to the DOCTYPE system identifier * (double-quoted) state. @@ -5309,7 +5249,7 @@ public class Tokenizer implements Locator { * system identifier to the empty string (not * missing), */ - clearStrBufBeforeUse(); + clearStrBuf(); /* * then switch to the DOCTYPE system identifier * (single-quoted) state. @@ -5558,7 +5498,7 @@ public class Tokenizer implements Locator { * Set the DOCTYPE token's system identifier to * the empty string (not missing), */ - clearStrBufBeforeUse(); + clearStrBuf(); /* * then switch to the DOCTYPE public identifier * (double-quoted) state. @@ -5574,7 +5514,7 @@ public class Tokenizer implements Locator { * Set the DOCTYPE token's public identifier to * the empty string (not missing), */ - clearStrBufBeforeUse(); + clearStrBuf(); /* * then switch to the DOCTYPE public identifier * (single-quoted) state. @@ -5645,7 +5585,7 @@ public class Tokenizer implements Locator { * token's system identifier to the empty string * (not missing), */ - clearStrBufBeforeUse(); + clearStrBuf(); /* * then switch to the DOCTYPE system identifier * (double-quoted) state. @@ -5658,7 +5598,7 @@ public class Tokenizer implements Locator { * system identifier to the empty string (not * missing), */ - clearStrBufBeforeUse(); + clearStrBuf(); /* * then switch to the DOCTYPE system identifier * (single-quoted) state. @@ -5874,9 +5814,6 @@ public class Tokenizer implements Locator { // ]NOCPP] private void initDoctypeFields() { - // Discard the characters "DOCTYPE" accumulated as a potential bogus - // comment into strBuf. - clearStrBufAfterUse(); doctypeName = ""; if (systemIdentifier != null) { Portability.releaseString(systemIdentifier); @@ -6164,6 +6101,7 @@ public class Tokenizer implements Locator { break eofloop; case MARKUP_DECLARATION_OPEN: errBogusComment(); + clearStrBuf(); emitComment(0, 0); break eofloop; case MARKUP_DECLARATION_HYPHEN: @@ -6519,7 +6457,6 @@ public class Tokenizer implements Locator { charRefBufLen - charRefBufMark); } } - charRefBufLen = 0; state = returnState; continue eofloop; /* @@ -6699,7 +6636,7 @@ public class Tokenizer implements Locator { } public void resetToDataState() { - clearStrBufAfterUse(); + strBufLen = 0; charRefBufLen = 0; stateSave = Tokenizer.DATA; // line = 1; XXX line numbers diff --git a/parser/html/nsHtml5Tokenizer.cpp b/parser/html/nsHtml5Tokenizer.cpp index 550d2da8ffac..24b3604d40b8 100644 --- a/parser/html/nsHtml5Tokenizer.cpp +++ b/parser/html/nsHtml5Tokenizer.cpp @@ -217,24 +217,26 @@ nsHtml5Tokenizer::emitOrAppendCharRefBuf(int32_t returnState) } else { if (charRefBufLen > 0) { tokenHandler->characters(charRefBuf, 0, charRefBufLen); - charRefBufLen = 0; } } } +void +nsHtml5Tokenizer::appendStrBuf(char16_t c) +{ + strBuf[strBufLen++] = c; +} + nsString* nsHtml5Tokenizer::strBufToString() { - nsString* str = nsHtml5Portability::newStringFromBuffer(strBuf, 0, strBufLen, tokenHandler); - clearStrBufAfterUse(); - return str; + return nsHtml5Portability::newStringFromBuffer(strBuf, 0, strBufLen, tokenHandler); } void nsHtml5Tokenizer::strBufToDoctypeName() { doctypeName = nsHtml5Portability::newLocalNameFromBuffer(strBuf, 0, strBufLen, interner); - clearStrBufAfterUse(); } void @@ -242,29 +244,26 @@ nsHtml5Tokenizer::emitStrBuf() { if (strBufLen > 0) { tokenHandler->characters(strBuf, 0, strBufLen); - clearStrBufAfterUse(); } } void nsHtml5Tokenizer::appendStrBuf(char16_t* buffer, int32_t offset, int32_t length) { - int32_t newLen = strBufLen + length; - MOZ_ASSERT(newLen <= strBuf.length, "Previous buffer length insufficient."); - if (MOZ_UNLIKELY(strBuf.length < newLen)) { - if (MOZ_UNLIKELY(!EnsureBufferSpace(length))) { - MOZ_CRASH("Unable to recover from buffer reallocation failure"); - } + int32_t reqLen = strBufLen + length; + if (strBuf.length < reqLen) { + jArray newBuf = jArray::newJArray(reqLen + (reqLen >> 1)); + nsHtml5ArrayCopy::arraycopy(strBuf, newBuf, strBuf.length); + strBuf = newBuf; } nsHtml5ArrayCopy::arraycopy(buffer, offset, strBuf, strBufLen, length); - strBufLen = newLen; + strBufLen = reqLen; } void nsHtml5Tokenizer::emitComment(int32_t provisionalHyphens, int32_t pos) { tokenHandler->comment(strBuf, 0, strBufLen - provisionalHyphens); - clearStrBufAfterUse(); cstart = pos + 1; } @@ -281,7 +280,6 @@ void nsHtml5Tokenizer::strBufToElementNameString() { tagName = nsHtml5ElementName::elementNameByBuffer(strBuf, 0, strBufLen, interner); - clearStrBufAfterUse(); } int32_t @@ -323,7 +321,6 @@ void nsHtml5Tokenizer::attributeNameComplete() { attributeName = nsHtml5AttributeName::nameByBuffer(strBuf, 0, strBufLen, interner); - clearStrBufAfterUse(); if (!attributes) { attributes = new nsHtml5HtmlAttributes(0); } @@ -341,8 +338,6 @@ nsHtml5Tokenizer::addAttributeWithoutValue() if (attributeName) { attributes->addAttribute(attributeName, nsHtml5Portability::newEmptyString(), attributeLine); attributeName = nullptr; - } else { - clearStrBufAfterUse(); } } @@ -437,8 +432,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu switch(c) { case '&': { flushChars(buf, pos); - MOZ_ASSERT(!charRefBufLen, "charRefBufLen not reset after previous use!"); - appendCharRefBuf(c); + clearCharRefBufAndAppend(c); setAdditionalAndRememberAmpersandLocation('\0'); returnState = state; state = P::transition(mViewSource, NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE, reconsume, pos); @@ -475,14 +469,12 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu c = checkChar(buf, pos); if (c >= 'A' && c <= 'Z') { endTag = false; - clearStrBufBeforeUse(); - appendStrBuf((char16_t) (c + 0x20)); + clearStrBufAndAppend((char16_t) (c + 0x20)); state = P::transition(mViewSource, NS_HTML5TOKENIZER_TAG_NAME, reconsume, pos); NS_HTML5_BREAK(tagopenloop); } else if (c >= 'a' && c <= 'z') { endTag = false; - clearStrBufBeforeUse(); - appendStrBuf(c); + clearStrBufAndAppend(c); state = P::transition(mViewSource, NS_HTML5TOKENIZER_TAG_NAME, reconsume, pos); NS_HTML5_BREAK(tagopenloop); } @@ -503,8 +495,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu if (P::reportErrors) { errProcessingInstruction(); } - clearStrBufBeforeUse(); - appendStrBuf(c); + clearStrBufAndAppend(c); state = P::transition(mViewSource, NS_HTML5TOKENIZER_BOGUS_COMMENT, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } @@ -631,8 +622,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu c += 0x20; } attributeLine = line; - clearStrBufBeforeUse(); - appendStrBuf(c); + clearStrBufAndAppend(c); state = P::transition(mViewSource, NS_HTML5TOKENIZER_ATTRIBUTE_NAME, reconsume, pos); NS_HTML5_BREAK(beforeattributenameloop); } @@ -725,13 +715,13 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu } case '\"': { attributeLine = line; - clearStrBufBeforeUse(); + clearStrBuf(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_DOUBLE_QUOTED, reconsume, pos); NS_HTML5_BREAK(beforeattributevalueloop); } case '&': { attributeLine = line; - clearStrBufBeforeUse(); + clearStrBuf(); reconsume = true; state = P::transition(mViewSource, NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_UNQUOTED, reconsume, pos); @@ -739,7 +729,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu } case '\'': { attributeLine = line; - clearStrBufBeforeUse(); + clearStrBuf(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_SINGLE_QUOTED, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } @@ -766,8 +756,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu } default: { attributeLine = line; - clearStrBufBeforeUse(); - appendStrBuf(c); + clearStrBufAndAppend(c); state = P::transition(mViewSource, NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_UNQUOTED, reconsume, pos); NS_HTML5_CONTINUE(stateloop); @@ -793,8 +782,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu NS_HTML5_BREAK(attributevaluedoublequotedloop); } case '&': { - MOZ_ASSERT(!charRefBufLen, "charRefBufLen not reset after previous use!"); - appendCharRefBuf(c); + clearCharRefBufAndAppend(c); setAdditionalAndRememberAmpersandLocation('\"'); returnState = state; state = P::transition(mViewSource, NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE, reconsume, pos); @@ -914,8 +902,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu NS_HTML5_CONTINUE(stateloop); } case '&': { - MOZ_ASSERT(!charRefBufLen, "charRefBufLen not reset after previous use!"); - appendCharRefBuf(c); + clearCharRefBufAndAppend(c); setAdditionalAndRememberAmpersandLocation('>'); returnState = state; state = P::transition(mViewSource, NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE, reconsume, pos); @@ -1000,8 +987,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu if (c >= 'A' && c <= 'Z') { c += 0x20; } - clearStrBufBeforeUse(); - appendStrBuf(c); + clearStrBufAndAppend(c); state = P::transition(mViewSource, NS_HTML5TOKENIZER_ATTRIBUTE_NAME, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } @@ -1016,23 +1002,20 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu c = checkChar(buf, pos); switch(c) { case '-': { - clearStrBufBeforeUse(); - appendStrBuf(c); + clearStrBufAndAppend(c); state = P::transition(mViewSource, NS_HTML5TOKENIZER_MARKUP_DECLARATION_HYPHEN, reconsume, pos); NS_HTML5_BREAK(markupdeclarationopenloop); } case 'd': case 'D': { - clearStrBufBeforeUse(); - appendStrBuf(c); + clearStrBufAndAppend(c); index = 0; state = P::transition(mViewSource, NS_HTML5TOKENIZER_MARKUP_DECLARATION_OCTYPE, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } case '[': { if (tokenHandler->cdataSectionAllowed()) { - clearStrBufBeforeUse(); - appendStrBuf(c); + clearStrBufAndAppend(c); index = 0; state = P::transition(mViewSource, NS_HTML5TOKENIZER_CDATA_START, reconsume, pos); NS_HTML5_CONTINUE(stateloop); @@ -1042,7 +1025,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu if (P::reportErrors) { errBogusComment(); } - clearStrBufBeforeUse(); + clearStrBuf(); reconsume = true; state = P::transition(mViewSource, NS_HTML5TOKENIZER_BOGUS_COMMENT, reconsume, pos); NS_HTML5_CONTINUE(stateloop); @@ -1062,7 +1045,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu NS_HTML5_BREAK(stateloop); } case '-': { - clearStrBufAfterOneHyphen(); + clearStrBuf(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_COMMENT_START, reconsume, pos); NS_HTML5_BREAK(markupdeclarationhyphenloop); } @@ -1326,7 +1309,6 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu index++; continue; } else { - clearStrBufAfterUse(); cstart = pos; reconsume = true; state = P::transition(mViewSource, NS_HTML5TOKENIZER_CDATA_SECTION, reconsume, pos); @@ -1434,8 +1416,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu NS_HTML5_CONTINUE(stateloop); } case '&': { - MOZ_ASSERT(!charRefBufLen, "charRefBufLen not reset after previous use!"); - appendCharRefBuf(c); + clearCharRefBufAndAppend(c); setAdditionalAndRememberAmpersandLocation('\''); returnState = state; state = P::transition(mViewSource, NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE, reconsume, pos); @@ -1667,7 +1648,6 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu } } bool earlyBreak = (c == ';' && charRefBufMark == charRefBufLen); - charRefBufLen = 0; if (!(returnState & NS_HTML5TOKENIZER_DATA_AND_RCDATA_MASK)) { cstart = earlyBreak ? pos + 1 : pos; } @@ -1761,7 +1741,6 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu decimalloop_end: ; } case NS_HTML5TOKENIZER_HANDLE_NCR_VALUE: { - charRefBufLen = 0; handleNcrValue(returnState); state = P::transition(mViewSource, returnState, reconsume, pos); NS_HTML5_CONTINUE(stateloop); @@ -1887,8 +1866,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu if (P::reportErrors) { errGarbageAfterLtSlash(); } - clearStrBufBeforeUse(); - appendStrBuf('\n'); + clearStrBufAndAppend('\n'); state = P::transition(mViewSource, NS_HTML5TOKENIZER_BOGUS_COMMENT, reconsume, pos); NS_HTML5_BREAK(stateloop); } @@ -1897,8 +1875,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu if (P::reportErrors) { errGarbageAfterLtSlash(); } - clearStrBufBeforeUse(); - appendStrBuf(c); + clearStrBufAndAppend('\n'); state = P::transition(mViewSource, NS_HTML5TOKENIZER_BOGUS_COMMENT, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } @@ -1911,16 +1888,14 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu } if (c >= 'a' && c <= 'z') { endTag = true; - clearStrBufBeforeUse(); - appendStrBuf(c); + clearStrBufAndAppend(c); state = P::transition(mViewSource, NS_HTML5TOKENIZER_TAG_NAME, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } else { if (P::reportErrors) { errGarbageAfterLtSlash(); } - clearStrBufBeforeUse(); - appendStrBuf(c); + clearStrBufAndAppend(c); state = P::transition(mViewSource, NS_HTML5TOKENIZER_BOGUS_COMMENT, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } @@ -1940,8 +1915,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu switch(c) { case '&': { flushChars(buf, pos); - MOZ_ASSERT(!charRefBufLen, "charRefBufLen not reset after previous use!"); - appendCharRefBuf(c); + clearCharRefBufAndAppend(c); setAdditionalAndRememberAmpersandLocation('\0'); returnState = state; state = P::transition(mViewSource, NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE, reconsume, pos); @@ -2015,7 +1989,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu switch(c) { case '/': { index = 0; - clearStrBufBeforeUse(); + clearStrBuf(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_NON_DATA_END_TAG_NAME, reconsume, pos); NS_HTML5_BREAK(rawtextrcdatalessthansignloop); } @@ -2059,7 +2033,6 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu switch(c) { case '\r': { silentCarriageReturn(); - clearStrBufAfterUse(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME, reconsume, pos); NS_HTML5_BREAK(stateloop); } @@ -2069,17 +2042,14 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu case ' ': case '\t': case '\f': { - clearStrBufAfterUse(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } case '/': { - clearStrBufAfterUse(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } case '>': { - clearStrBufAfterUse(); state = P::transition(mViewSource, emitCurrentTagToken(false, pos), reconsume, pos); if (shouldSuspend) { NS_HTML5_BREAK(stateloop); @@ -2223,7 +2193,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu switch(c) { case '/': { index = 0; - clearStrBufBeforeUse(); + clearStrBuf(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_NON_DATA_END_TAG_NAME, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } @@ -2408,7 +2378,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu switch(c) { case '/': { index = 0; - clearStrBufBeforeUse(); + clearStrBuf(); returnState = NS_HTML5TOKENIZER_SCRIPT_DATA_ESCAPED; state = P::transition(mViewSource, NS_HTML5TOKENIZER_NON_DATA_END_TAG_NAME, reconsume, pos); NS_HTML5_CONTINUE(stateloop); @@ -2764,8 +2734,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu if (c >= 'A' && c <= 'Z') { c += 0x20; } - clearStrBufBeforeUse(); - appendStrBuf(c); + clearStrBufAndAppend(c); state = P::transition(mViewSource, NS_HTML5TOKENIZER_DOCTYPE_NAME, reconsume, pos); NS_HTML5_BREAK(beforedoctypenameloop); } @@ -2917,7 +2886,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu if (P::reportErrors) { errNoSpaceBetweenDoctypePublicKeywordAndQuote(); } - clearStrBufBeforeUse(); + clearStrBuf(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } @@ -2925,7 +2894,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu if (P::reportErrors) { errNoSpaceBetweenDoctypePublicKeywordAndQuote(); } - clearStrBufBeforeUse(); + clearStrBuf(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } @@ -2967,12 +2936,12 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu continue; } case '\"': { - clearStrBufBeforeUse(); + clearStrBuf(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED, reconsume, pos); NS_HTML5_BREAK(beforedoctypepublicidentifierloop); } case '\'': { - clearStrBufBeforeUse(); + clearStrBuf(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } @@ -3065,7 +3034,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu if (P::reportErrors) { errNoSpaceBetweenPublicAndSystemIds(); } - clearStrBufBeforeUse(); + clearStrBuf(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } @@ -3073,7 +3042,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu if (P::reportErrors) { errNoSpaceBetweenPublicAndSystemIds(); } - clearStrBufBeforeUse(); + clearStrBuf(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } @@ -3111,12 +3080,12 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu NS_HTML5_CONTINUE(stateloop); } case '\"': { - clearStrBufBeforeUse(); + clearStrBuf(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED, reconsume, pos); NS_HTML5_BREAK(betweendoctypepublicandsystemidentifiersloop); } case '\'': { - clearStrBufBeforeUse(); + clearStrBuf(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } @@ -3288,7 +3257,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu if (P::reportErrors) { errNoSpaceBetweenDoctypeSystemKeywordAndQuote(); } - clearStrBufBeforeUse(); + clearStrBuf(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } @@ -3296,7 +3265,7 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu if (P::reportErrors) { errNoSpaceBetweenDoctypeSystemKeywordAndQuote(); } - clearStrBufBeforeUse(); + clearStrBuf(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } @@ -3338,12 +3307,12 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu continue; } case '\"': { - clearStrBufBeforeUse(); + clearStrBuf(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED, reconsume, pos); NS_HTML5_CONTINUE(stateloop); } case '\'': { - clearStrBufBeforeUse(); + clearStrBuf(); state = P::transition(mViewSource, NS_HTML5TOKENIZER_DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED, reconsume, pos); NS_HTML5_BREAK(beforedoctypesystemidentifierloop); } @@ -3491,7 +3460,6 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu void nsHtml5Tokenizer::initDoctypeFields() { - clearStrBufAfterUse(); doctypeName = nsHtml5Atoms::emptystring; if (systemIdentifier) { nsHtml5Portability::releaseString(systemIdentifier); @@ -3644,6 +3612,7 @@ nsHtml5Tokenizer::eof() } case NS_HTML5TOKENIZER_MARKUP_DECLARATION_OPEN: { errBogusComment(); + clearStrBuf(); emitComment(0, 0); NS_HTML5_BREAK(eofloop); } @@ -3849,7 +3818,6 @@ nsHtml5Tokenizer::eof() tokenHandler->characters(charRefBuf, charRefBufMark, charRefBufLen - charRefBufMark); } } - charRefBufLen = 0; state = returnState; NS_HTML5_CONTINUE(eofloop); } @@ -3972,7 +3940,7 @@ nsHtml5Tokenizer::isInDataState() void nsHtml5Tokenizer::resetToDataState() { - clearStrBufAfterUse(); + strBufLen = 0; charRefBufLen = 0; stateSave = NS_HTML5TOKENIZER_DATA; lastCR = false; diff --git a/parser/html/nsHtml5Tokenizer.h b/parser/html/nsHtml5Tokenizer.h index 9848a502b3a8..6a6a8ed39b78 100644 --- a/parser/html/nsHtml5Tokenizer.h +++ b/parser/html/nsHtml5Tokenizer.h @@ -158,40 +158,28 @@ class nsHtml5Tokenizer private: inline void appendCharRefBuf(char16_t c) { - MOZ_RELEASE_ASSERT(charRefBufLen < charRefBuf.length, "Attempted to overrun charRefBuf!"); charRefBuf[charRefBufLen++] = c; } + inline void clearCharRefBufAndAppend(char16_t c) + { + charRefBuf[0] = c; + charRefBufLen = 1; + } + void emitOrAppendCharRefBuf(int32_t returnState); - inline void clearStrBufAfterUse() + inline void clearStrBufAndAppend(char16_t c) + { + strBuf[0] = c; + strBufLen = 1; + } + + inline void clearStrBuf() { strBufLen = 0; } - inline void clearStrBufBeforeUse() - { - MOZ_ASSERT(!strBufLen, "strBufLen not reset after previous use!"); - strBufLen = 0; - } - - inline void clearStrBufAfterOneHyphen() - { - MOZ_ASSERT(strBufLen == 1, "strBufLen length not one!"); - MOZ_ASSERT(strBuf[0] == '-', "strBuf does not start with a hyphen!"); - strBufLen = 0; - } - - inline void appendStrBuf(char16_t c) - { - MOZ_ASSERT(strBufLen < strBuf.length, "Previous buffer length insufficient."); - if (MOZ_UNLIKELY(strBufLen == strBuf.length)) { - if (MOZ_UNLIKELY(!EnsureBufferSpace(1))) { - MOZ_CRASH("Unable to recover from buffer reallocation failure"); - } - } - strBuf[strBufLen++] = c; - } - + void appendStrBuf(char16_t c); protected: nsString* strBufToString(); private: @@ -212,7 +200,6 @@ class nsHtml5Tokenizer inline void appendCharRefBufToStrBuf() { appendStrBuf(charRefBuf, 0, charRefBufLen); - charRefBufLen = 0; } void emitComment(int32_t provisionalHyphens, int32_t pos); diff --git a/parser/html/nsHtml5TreeBuilderCppSupplement.h b/parser/html/nsHtml5TreeBuilderCppSupplement.h index ce040183f57b..4cd030a3e7b4 100644 --- a/parser/html/nsHtml5TreeBuilderCppSupplement.h +++ b/parser/html/nsHtml5TreeBuilderCppSupplement.h @@ -955,8 +955,8 @@ nsHtml5TreeBuilder::elementPopped(int32_t aNamespace, nsIAtom* aName, nsIContent void nsHtml5TreeBuilder::accumulateCharacters(const char16_t* aBuf, int32_t aStart, int32_t aLength) { - MOZ_RELEASE_ASSERT(charBufferLen + aLength <= charBuffer.length, - "About to memcpy past the end of the buffer!"); + MOZ_ASSERT(charBufferLen + aLength <= charBuffer.length, + "About to memcpy past the end of the buffer!"); memcpy(charBuffer + charBufferLen, aBuf + aStart, sizeof(char16_t) * aLength); charBufferLen += aLength; } From 905a450ea2ec2cc36eaa7db01a72ce4e353870b9 Mon Sep 17 00:00:00 2001 From: Eugen Sawin Date: Wed, 10 Aug 2016 20:54:37 +0200 Subject: [PATCH 030/102] Bug 1291424 - [1.4] Extract and cache libs on first run. r=glandium,snorp --- mobile/android/confvars.sh | 6 ------ old-configure.in | 1 + 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/mobile/android/confvars.sh b/mobile/android/confvars.sh index 665fc86803bd..448f074cd70e 100644 --- a/mobile/android/confvars.sh +++ b/mobile/android/confvars.sh @@ -37,12 +37,6 @@ MOZ_APP_ID={aa3c5121-dab2-40e2-81ca-7ea25febc110} MOZ_APP_STATIC_INI=1 -# Enable on-demand decompression. This requires a host compile toolchain to -# build szip to use during packaging. -if test "$COMPILE_ENVIRONMENT"; then -MOZ_ENABLE_SZIP=1 -fi - # Enable second screen using native Android libraries. MOZ_NATIVE_DEVICES=1 diff --git a/old-configure.in b/old-configure.in index 08e2a4c0e966..8ebc5ec6640e 100644 --- a/old-configure.in +++ b/old-configure.in @@ -1309,6 +1309,7 @@ AC_SUBST_LIST(SSSE3_FLAGS) AC_SUBST(MOZ_LINKER) if test -n "$MOZ_LINKER"; then AC_DEFINE(MOZ_LINKER) + MOZ_LINKER_EXTRACT=1 fi dnl Only one oddball right now (QNX), but this gives us flexibility From f6db690c95f08bc54f374b197c459311b3eff995 Mon Sep 17 00:00:00 2001 From: Nicholas Hurley Date: Thu, 22 Sep 2016 09:38:26 -0700 Subject: [PATCH 031/102] Bug 1303212 - Don't check for CLOCK_MONOTONIC on darwin r=glandium MozReview-Commit-ID: 9Ppn5jzcjbP --- js/src/old-configure.in | 50 ++++++++++++++++++++++++----------------- old-configure.in | 50 ++++++++++++++++++++++++----------------- 2 files changed, 58 insertions(+), 42 deletions(-) diff --git a/js/src/old-configure.in b/js/src/old-configure.in index cbc38b9d002d..8fb4c96f01e8 100644 --- a/js/src/old-configure.in +++ b/js/src/old-configure.in @@ -1216,27 +1216,35 @@ AC_FUNC_MEMCMP AC_CHECK_FUNCS([getc_unlocked _getc_nolock gmtime_r localtime_r pthread_getname_np]) dnl check for clock_gettime(), the CLOCK_MONOTONIC clock -AC_CACHE_CHECK(for clock_gettime(CLOCK_MONOTONIC), - ac_cv_clock_monotonic, - [for libs in "" -lrt; do - _SAVE_LIBS="$LIBS" - LIBS="$LIBS $libs" - AC_TRY_LINK([#include ], - [ struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); ], - ac_cv_clock_monotonic=$libs - LIBS="$_SAVE_LIBS" - break, - ac_cv_clock_monotonic=no) - LIBS="$_SAVE_LIBS" - done]) -if test "$ac_cv_clock_monotonic" != "no"; then - HAVE_CLOCK_MONOTONIC=1 - REALTIME_LIBS=$ac_cv_clock_monotonic - AC_DEFINE(HAVE_CLOCK_MONOTONIC) - AC_SUBST(HAVE_CLOCK_MONOTONIC) - AC_SUBST_LIST(REALTIME_LIBS) -fi +dnl avoid this on Darwin, since depending on your system config, we may think +dnl it exists but it really doesn't +case "$OS_TARGET" in +Darwin) + ;; +*) + AC_CACHE_CHECK(for clock_gettime(CLOCK_MONOTONIC), + ac_cv_clock_monotonic, + [for libs in "" -lrt; do + _SAVE_LIBS="$LIBS" + LIBS="$LIBS $libs" + AC_TRY_LINK([#include ], + [ struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); ], + ac_cv_clock_monotonic=$libs + LIBS="$_SAVE_LIBS" + break, + ac_cv_clock_monotonic=no) + LIBS="$_SAVE_LIBS" + done]) + if test "$ac_cv_clock_monotonic" != "no"; then + HAVE_CLOCK_MONOTONIC=1 + REALTIME_LIBS=$ac_cv_clock_monotonic + AC_DEFINE(HAVE_CLOCK_MONOTONIC) + AC_SUBST(HAVE_CLOCK_MONOTONIC) + AC_SUBST_LIST(REALTIME_LIBS) + fi + ;; +esac dnl Checks for math functions. dnl ======================================================== diff --git a/old-configure.in b/old-configure.in index 8ebc5ec6640e..641aa850858f 100644 --- a/old-configure.in +++ b/old-configure.in @@ -1667,27 +1667,35 @@ AC_FUNC_MEMCMP AC_CHECK_FUNCS(stat64 lstat64 truncate64 statvfs64 statvfs statfs64 statfs getpagesize gmtime_r localtime_r arc4random arc4random_buf mallinfo gettid lchown setpriority strerror syscall) dnl check for clock_gettime(), the CLOCK_MONOTONIC clock -AC_CACHE_CHECK(for clock_gettime(CLOCK_MONOTONIC), - ac_cv_clock_monotonic, - [for libs in "" -lrt; do - _SAVE_LIBS="$LIBS" - LIBS="$LIBS $libs" - AC_TRY_LINK([#include ], - [ struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); ], - ac_cv_clock_monotonic=$libs - LIBS="$_SAVE_LIBS" - break, - ac_cv_clock_monotonic=no) - LIBS="$_SAVE_LIBS" - done]) -if test "$ac_cv_clock_monotonic" != "no"; then - HAVE_CLOCK_MONOTONIC=1 - REALTIME_LIBS=$ac_cv_clock_monotonic - AC_DEFINE(HAVE_CLOCK_MONOTONIC) - AC_SUBST(HAVE_CLOCK_MONOTONIC) - AC_SUBST_LIST(REALTIME_LIBS) -fi +dnl avoid this on Darwin, since depending on your system config, we may think +dnl it exists but it really doesn't +case "$OS_TARGET" in +Darwin) + ;; +*) + AC_CACHE_CHECK(for clock_gettime(CLOCK_MONOTONIC), + ac_cv_clock_monotonic, + [for libs in "" -lrt; do + _SAVE_LIBS="$LIBS" + LIBS="$LIBS $libs" + AC_TRY_LINK([#include ], + [ struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); ], + ac_cv_clock_monotonic=$libs + LIBS="$_SAVE_LIBS" + break, + ac_cv_clock_monotonic=no) + LIBS="$_SAVE_LIBS" + done]) + if test "$ac_cv_clock_monotonic" != "no"; then + HAVE_CLOCK_MONOTONIC=1 + REALTIME_LIBS=$ac_cv_clock_monotonic + AC_DEFINE(HAVE_CLOCK_MONOTONIC) + AC_SUBST(HAVE_CLOCK_MONOTONIC) + AC_SUBST_LIST(REALTIME_LIBS) + fi + ;; +esac AC_CACHE_CHECK(for pthread_cond_timedwait_monotonic_np, ac_cv_pthread_cond_timedwait_monotonic_np, From 13501a2bea7fd2ab40a9c115c058460012712642 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Tue, 27 Sep 2016 14:15:17 +0100 Subject: [PATCH 032/102] Bug 1296661 - Use MOZ_MUST_USE in Reflect.parse implementation r=njn --- js/src/builtin/ReflectParse.cpp | 229 ++++++++++++++++---------------- 1 file changed, 118 insertions(+), 111 deletions(-) diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp index 987dbff902e5..5bf8a9624757 100644 --- a/js/src/builtin/ReflectParse.cpp +++ b/js/src/builtin/ReflectParse.cpp @@ -254,7 +254,7 @@ class NodeBuilder userv(c) {} - bool init(HandleObject userobj = nullptr) { + MOZ_MUST_USE bool init(HandleObject userobj = nullptr) { if (src) { if (!atomValue(src, &srcval)) return false; @@ -305,8 +305,8 @@ class NodeBuilder } private: - bool callbackHelper(HandleValue fun, const InvokeArgs& args, size_t i, - TokenPos* pos, MutableHandleValue dst) + MOZ_MUST_USE bool callbackHelper(HandleValue fun, const InvokeArgs& args, size_t i, + TokenPos* pos, MutableHandleValue dst) { // The end of the implementation of callback(). All arguments except // loc have already been stored in range [0, i). @@ -322,8 +322,8 @@ class NodeBuilder // that convert to HandleValue, so this isn't as template-y as it seems, // just variadic. template - bool callbackHelper(HandleValue fun, const InvokeArgs& args, size_t i, - HandleValue head, Arguments&&... tail) + MOZ_MUST_USE bool callbackHelper(HandleValue fun, const InvokeArgs& args, size_t i, + HandleValue head, Arguments&&... tail) { // Recursive loop to store the arguments into args. This eventually // bottoms out in a call to the non-template callbackHelper() above. @@ -336,7 +336,7 @@ class NodeBuilder // bool callback(HandleValue fun, HandleValue... args, TokenPos* pos, // MutableHandleValue dst); template - bool callback(HandleValue fun, Arguments&&... args) { + MOZ_MUST_USE bool callback(HandleValue fun, Arguments&&... args) { InvokeArgs iargs(cx); if (!iargs.init(sizeof...(args) - 2 + size_t(saveLoc))) return false; @@ -353,7 +353,7 @@ class NodeBuilder return v.isMagic(JS_SERIALIZE_NO_NODE) ? JS::UndefinedHandleValue : v; } - bool atomValue(const char* s, MutableHandleValue dst) { + MOZ_MUST_USE bool atomValue(const char* s, MutableHandleValue dst) { /* * Bug 575416: instead of Atomize, lookup constant atoms in tbl file */ @@ -365,7 +365,7 @@ class NodeBuilder return true; } - bool newObject(MutableHandleObject dst) { + MOZ_MUST_USE bool newObject(MutableHandleObject dst) { RootedPlainObject nobj(cx, NewBuiltinClassInstance(cx)); if (!nobj) return false; @@ -374,11 +374,11 @@ class NodeBuilder return true; } - bool newArray(NodeVector& elts, MutableHandleValue dst); + MOZ_MUST_USE bool newArray(NodeVector& elts, MutableHandleValue dst); - bool createNode(ASTType type, TokenPos* pos, MutableHandleObject dst); + MOZ_MUST_USE bool createNode(ASTType type, TokenPos* pos, MutableHandleObject dst); - bool newNodeHelper(HandleObject obj, MutableHandleValue dst) { + MOZ_MUST_USE bool newNodeHelper(HandleObject obj, MutableHandleValue dst) { // The end of the implementation of newNode(). MOZ_ASSERT(obj); dst.setObject(*obj); @@ -386,8 +386,8 @@ class NodeBuilder } template - bool newNodeHelper(HandleObject obj, const char *name, HandleValue value, - Arguments&&... rest) + MOZ_MUST_USE bool newNodeHelper(HandleObject obj, const char *name, HandleValue value, + Arguments&&... rest) { // Recursive loop to define properties. Note that the newNodeHelper() // call below passes two fewer arguments than we received, as we omit @@ -405,14 +405,14 @@ class NodeBuilder // {const char *name0, HandleValue value0,}... // MutableHandleValue dst); template - bool newNode(ASTType type, TokenPos* pos, Arguments&&... args) { + MOZ_MUST_USE bool newNode(ASTType type, TokenPos* pos, Arguments&&... args) { RootedObject node(cx); return createNode(type, pos, &node) && newNodeHelper(node, Forward(args)...); } - bool listNode(ASTType type, const char* propName, NodeVector& elts, TokenPos* pos, - MutableHandleValue dst) { + MOZ_MUST_USE bool listNode(ASTType type, const char* propName, NodeVector& elts, TokenPos* pos, + MutableHandleValue dst) { RootedValue array(cx); if (!newArray(elts, &array)) return false; @@ -424,7 +424,7 @@ class NodeBuilder return newNode(type, pos, propName, array, dst); } - bool defineProperty(HandleObject obj, const char* name, HandleValue val) { + MOZ_MUST_USE bool defineProperty(HandleObject obj, const char* name, HandleValue val) { MOZ_ASSERT_IF(val.isMagic(), val.whyMagic() == JS_SERIALIZE_NO_NODE); /* @@ -439,9 +439,9 @@ class NodeBuilder return DefineProperty(cx, obj, atom->asPropertyName(), optVal); } - bool newNodeLoc(TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool newNodeLoc(TokenPos* pos, MutableHandleValue dst); - bool setNodeLoc(HandleObject node, TokenPos* pos); + MOZ_MUST_USE bool setNodeLoc(HandleObject node, TokenPos* pos); public: /* @@ -457,175 +457,183 @@ class NodeBuilder * misc nodes */ - bool program(NodeVector& elts, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool program(NodeVector& elts, TokenPos* pos, MutableHandleValue dst); - bool literal(HandleValue val, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool literal(HandleValue val, TokenPos* pos, MutableHandleValue dst); - bool identifier(HandleValue name, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool identifier(HandleValue name, TokenPos* pos, MutableHandleValue dst); - bool function(ASTType type, TokenPos* pos, - HandleValue id, NodeVector& args, NodeVector& defaults, - HandleValue body, HandleValue rest, GeneratorStyle generatorStyle, - bool isExpression, MutableHandleValue dst); + MOZ_MUST_USE bool function(ASTType type, TokenPos* pos, + HandleValue id, NodeVector& args, NodeVector& defaults, + HandleValue body, HandleValue rest, GeneratorStyle generatorStyle, + bool isExpression, MutableHandleValue dst); - bool variableDeclarator(HandleValue id, HandleValue init, TokenPos* pos, - MutableHandleValue dst); + MOZ_MUST_USE bool variableDeclarator(HandleValue id, HandleValue init, TokenPos* pos, + MutableHandleValue dst); - bool switchCase(HandleValue expr, NodeVector& elts, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool switchCase(HandleValue expr, NodeVector& elts, TokenPos* pos, MutableHandleValue dst); - bool catchClause(HandleValue var, HandleValue guard, HandleValue body, TokenPos* pos, - MutableHandleValue dst); + MOZ_MUST_USE bool catchClause(HandleValue var, HandleValue guard, HandleValue body, TokenPos* pos, + MutableHandleValue dst); - bool prototypeMutation(HandleValue val, TokenPos* pos, MutableHandleValue dst); - bool propertyInitializer(HandleValue key, HandleValue val, PropKind kind, bool isShorthand, - bool isMethod, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool prototypeMutation(HandleValue val, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool propertyInitializer(HandleValue key, HandleValue val, PropKind kind, + bool isShorthand, bool isMethod, TokenPos* pos, + MutableHandleValue dst); /* * statements */ - bool blockStatement(NodeVector& elts, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool blockStatement(NodeVector& elts, TokenPos* pos, MutableHandleValue dst); - bool expressionStatement(HandleValue expr, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool expressionStatement(HandleValue expr, TokenPos* pos, MutableHandleValue dst); - bool emptyStatement(TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool emptyStatement(TokenPos* pos, MutableHandleValue dst); - bool ifStatement(HandleValue test, HandleValue cons, HandleValue alt, TokenPos* pos, + MOZ_MUST_USE bool ifStatement(HandleValue test, HandleValue cons, HandleValue alt, TokenPos* pos, MutableHandleValue dst); - bool breakStatement(HandleValue label, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool breakStatement(HandleValue label, TokenPos* pos, MutableHandleValue dst); - bool continueStatement(HandleValue label, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool continueStatement(HandleValue label, TokenPos* pos, MutableHandleValue dst); - bool labeledStatement(HandleValue label, HandleValue stmt, TokenPos* pos, + MOZ_MUST_USE bool labeledStatement(HandleValue label, HandleValue stmt, TokenPos* pos, MutableHandleValue dst); - bool throwStatement(HandleValue arg, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool throwStatement(HandleValue arg, TokenPos* pos, MutableHandleValue dst); - bool returnStatement(HandleValue arg, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool returnStatement(HandleValue arg, TokenPos* pos, MutableHandleValue dst); - bool forStatement(HandleValue init, HandleValue test, HandleValue update, HandleValue stmt, + MOZ_MUST_USE bool forStatement(HandleValue init, HandleValue test, HandleValue update, HandleValue stmt, TokenPos* pos, MutableHandleValue dst); - bool forInStatement(HandleValue var, HandleValue expr, HandleValue stmt, - bool isForEach, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool forInStatement(HandleValue var, HandleValue expr, HandleValue stmt, + bool isForEach, TokenPos* pos, MutableHandleValue dst); - bool forOfStatement(HandleValue var, HandleValue expr, HandleValue stmt, TokenPos* pos, - MutableHandleValue dst); + MOZ_MUST_USE bool forOfStatement(HandleValue var, HandleValue expr, HandleValue stmt, TokenPos* pos, + MutableHandleValue dst); - bool withStatement(HandleValue expr, HandleValue stmt, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool withStatement(HandleValue expr, HandleValue stmt, TokenPos* pos, MutableHandleValue dst); - bool whileStatement(HandleValue test, HandleValue stmt, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool whileStatement(HandleValue test, HandleValue stmt, TokenPos* pos, MutableHandleValue dst); - bool doWhileStatement(HandleValue stmt, HandleValue test, TokenPos* pos, - MutableHandleValue dst); + MOZ_MUST_USE bool doWhileStatement(HandleValue stmt, HandleValue test, TokenPos* pos, + MutableHandleValue dst); - bool switchStatement(HandleValue disc, NodeVector& elts, bool lexical, TokenPos* pos, - MutableHandleValue dst); + MOZ_MUST_USE bool switchStatement(HandleValue disc, NodeVector& elts, bool lexical, TokenPos* pos, + MutableHandleValue dst); - bool tryStatement(HandleValue body, NodeVector& guarded, HandleValue unguarded, - HandleValue finally, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool tryStatement(HandleValue body, NodeVector& guarded, HandleValue unguarded, + HandleValue finally, TokenPos* pos, MutableHandleValue dst); - bool debuggerStatement(TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool debuggerStatement(TokenPos* pos, MutableHandleValue dst); - bool importDeclaration(NodeVector& elts, HandleValue moduleSpec, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool importDeclaration(NodeVector& elts, HandleValue moduleSpec, TokenPos* pos, MutableHandleValue dst); - bool importSpecifier(HandleValue importName, HandleValue bindingName, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool importSpecifier(HandleValue importName, HandleValue bindingName, TokenPos* pos, MutableHandleValue dst); - bool exportDeclaration(HandleValue decl, NodeVector& elts, HandleValue moduleSpec, - HandleValue isDefault, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool exportDeclaration(HandleValue decl, NodeVector& elts, HandleValue moduleSpec, + HandleValue isDefault, TokenPos* pos, MutableHandleValue dst); - bool exportSpecifier(HandleValue bindingName, HandleValue exportName, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool exportSpecifier(HandleValue bindingName, HandleValue exportName, TokenPos* pos, MutableHandleValue dst); - bool exportBatchSpecifier(TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool exportBatchSpecifier(TokenPos* pos, MutableHandleValue dst); - bool classDefinition(bool expr, HandleValue name, HandleValue heritage, HandleValue block, TokenPos* pos, - MutableHandleValue dst); - bool classMethods(NodeVector& methods, MutableHandleValue dst); - bool classMethod(HandleValue name, HandleValue body, PropKind kind, bool isStatic, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool classDefinition(bool expr, HandleValue name, HandleValue heritage, + HandleValue block, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool classMethods(NodeVector& methods, MutableHandleValue dst); + MOZ_MUST_USE bool classMethod(HandleValue name, HandleValue body, PropKind kind, bool isStatic, + TokenPos* pos, MutableHandleValue dst); /* * expressions */ - bool binaryExpression(BinaryOperator op, HandleValue left, HandleValue right, TokenPos* pos, - MutableHandleValue dst); + MOZ_MUST_USE bool binaryExpression(BinaryOperator op, HandleValue left, HandleValue right, + TokenPos* pos, MutableHandleValue dst); - bool unaryExpression(UnaryOperator op, HandleValue expr, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool unaryExpression(UnaryOperator op, HandleValue expr, TokenPos* pos, + MutableHandleValue dst); - bool assignmentExpression(AssignmentOperator op, HandleValue lhs, HandleValue rhs, - TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool assignmentExpression(AssignmentOperator op, HandleValue lhs, HandleValue rhs, + TokenPos* pos, MutableHandleValue dst); - bool updateExpression(HandleValue expr, bool incr, bool prefix, TokenPos* pos, - MutableHandleValue dst); + MOZ_MUST_USE bool updateExpression(HandleValue expr, bool incr, bool prefix, TokenPos* pos, + MutableHandleValue dst); - bool logicalExpression(bool lor, HandleValue left, HandleValue right, TokenPos* pos, - MutableHandleValue dst); + MOZ_MUST_USE bool logicalExpression(bool lor, HandleValue left, HandleValue right, TokenPos* pos, + MutableHandleValue dst); - bool conditionalExpression(HandleValue test, HandleValue cons, HandleValue alt, TokenPos* pos, - MutableHandleValue dst); + MOZ_MUST_USE bool conditionalExpression(HandleValue test, HandleValue cons, HandleValue alt, + TokenPos* pos, MutableHandleValue dst); - bool sequenceExpression(NodeVector& elts, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool sequenceExpression(NodeVector& elts, TokenPos* pos, MutableHandleValue dst); - bool newExpression(HandleValue callee, NodeVector& args, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool newExpression(HandleValue callee, NodeVector& args, TokenPos* pos, + MutableHandleValue dst); - bool callExpression(HandleValue callee, NodeVector& args, TokenPos* pos, - MutableHandleValue dst); + MOZ_MUST_USE bool callExpression(HandleValue callee, NodeVector& args, TokenPos* pos, + MutableHandleValue dst); - bool memberExpression(bool computed, HandleValue expr, HandleValue member, TokenPos* pos, - MutableHandleValue dst); + MOZ_MUST_USE bool memberExpression(bool computed, HandleValue expr, HandleValue member, + TokenPos* pos, MutableHandleValue dst); - bool arrayExpression(NodeVector& elts, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool arrayExpression(NodeVector& elts, TokenPos* pos, MutableHandleValue dst); - bool templateLiteral(NodeVector& elts, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool templateLiteral(NodeVector& elts, TokenPos* pos, MutableHandleValue dst); - bool taggedTemplate(HandleValue callee, NodeVector& args, TokenPos* pos, - MutableHandleValue dst); + MOZ_MUST_USE bool taggedTemplate(HandleValue callee, NodeVector& args, TokenPos* pos, + MutableHandleValue dst); - bool callSiteObj(NodeVector& raw, NodeVector& cooked, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool callSiteObj(NodeVector& raw, NodeVector& cooked, TokenPos* pos, + MutableHandleValue dst); - bool spreadExpression(HandleValue expr, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool spreadExpression(HandleValue expr, TokenPos* pos, MutableHandleValue dst); - bool computedName(HandleValue name, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool computedName(HandleValue name, TokenPos* pos, MutableHandleValue dst); - bool objectExpression(NodeVector& elts, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool objectExpression(NodeVector& elts, TokenPos* pos, MutableHandleValue dst); - bool thisExpression(TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool thisExpression(TokenPos* pos, MutableHandleValue dst); - bool yieldExpression(HandleValue arg, YieldKind kind, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool yieldExpression(HandleValue arg, YieldKind kind, TokenPos* pos, + MutableHandleValue dst); - bool comprehensionBlock(HandleValue patt, HandleValue src, bool isForEach, bool isForOf, TokenPos* pos, - MutableHandleValue dst); - bool comprehensionIf(HandleValue test, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool comprehensionBlock(HandleValue patt, HandleValue src, bool isForEach, + bool isForOf, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool comprehensionIf(HandleValue test, TokenPos* pos, MutableHandleValue dst); - bool comprehensionExpression(HandleValue body, NodeVector& blocks, HandleValue filter, - bool isLegacy, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool comprehensionExpression(HandleValue body, NodeVector& blocks, + HandleValue filter, bool isLegacy, TokenPos* pos, + MutableHandleValue dst); - bool generatorExpression(HandleValue body, NodeVector& blocks, HandleValue filter, - bool isLegacy, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool generatorExpression(HandleValue body, NodeVector& blocks, HandleValue filter, + bool isLegacy, TokenPos* pos, MutableHandleValue dst); - bool metaProperty(HandleValue meta, HandleValue property, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool metaProperty(HandleValue meta, HandleValue property, TokenPos* pos, + MutableHandleValue dst); - bool super(TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool super(TokenPos* pos, MutableHandleValue dst); /* * declarations */ - bool variableDeclaration(NodeVector& elts, VarDeclKind kind, TokenPos* pos, - MutableHandleValue dst); + MOZ_MUST_USE bool variableDeclaration(NodeVector& elts, VarDeclKind kind, TokenPos* pos, + MutableHandleValue dst); /* * patterns */ - bool arrayPattern(NodeVector& elts, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool arrayPattern(NodeVector& elts, TokenPos* pos, MutableHandleValue dst); - bool objectPattern(NodeVector& elts, TokenPos* pos, MutableHandleValue dst); + MOZ_MUST_USE bool objectPattern(NodeVector& elts, TokenPos* pos, MutableHandleValue dst); - bool propertyPattern(HandleValue key, HandleValue patt, bool isShorthand, TokenPos* pos, - MutableHandleValue dst); + MOZ_MUST_USE bool propertyPattern(HandleValue key, HandleValue patt, bool isShorthand, + TokenPos* pos, MutableHandleValue dst); }; } /* anonymous namespace */ @@ -734,8 +742,7 @@ NodeBuilder::setNodeLoc(HandleObject node, TokenPos* pos) { if (!saveLoc) { RootedValue nullVal(cx, NullValue()); - defineProperty(node, "loc", nullVal); - return true; + return defineProperty(node, "loc", nullVal); } RootedValue loc(cx); From f84225ca512ec41db4d78437e42c826f9094f5e0 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Tue, 27 Sep 2016 14:16:08 +0100 Subject: [PATCH 033/102] Bug 1305220 - Also cancel off thread Ion compilation on OOM r=jandem --- js/src/jit-test/tests/gc/bug-1305220.js | 23 +++++++++++++++++++++++ js/src/vm/TypeInference.cpp | 1 + 2 files changed, 24 insertions(+) create mode 100644 js/src/jit-test/tests/gc/bug-1305220.js diff --git a/js/src/jit-test/tests/gc/bug-1305220.js b/js/src/jit-test/tests/gc/bug-1305220.js new file mode 100644 index 000000000000..30d3fa26038e --- /dev/null +++ b/js/src/jit-test/tests/gc/bug-1305220.js @@ -0,0 +1,23 @@ +// |jit-test| allow-oom +if (!('oomAfterAllocations' in this)) + quit(); +s = newGlobal(); +evalcx("\ + gczeal(10, 2);\ + k = {\ + [Symbol]() {}\ + };\ +", s); +gczeal(0); +evalcx("\ + var g = newGlobal();\ + b = new Debugger;\ + g.h = function() {\ + g.oomAfterAllocations(1);\ + };\ + g.eval(\"\" + function f() g());\ + g.eval(\"\" + function g() h());\ + g.eval(\"(\" + function() {\ + f();\ + } + \")()\");\ +", s); diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index f8a35fc35f0e..4a019725232d 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -4481,6 +4481,7 @@ AutoClearTypeInferenceStateOnOOM::~AutoClearTypeInferenceStateOnOOM() { if (oom) { JSRuntime* rt = zone->runtimeFromMainThread(); + js::CancelOffThreadIonCompile(rt); zone->setPreservingCode(false); zone->discardJitCode(rt->defaultFreeOp()); zone->types.clearAllNewScriptsOnOOM(); From cc4bbce3d9a8f1aec905fdbdc3e82a83ddba754b Mon Sep 17 00:00:00 2001 From: Avi Halachmi Date: Tue, 27 Sep 2016 16:43:36 +0300 Subject: [PATCH 034/102] Bug 1189901: part 1: remove code redundancy between tscrollx and tp5o_scroll. r=jmaher --- .../talos/talos/pageloader/chrome/tscroll.js | 22 +++++++++---------- testing/talos/talos/tests/scroll/iframe.svg | 2 +- testing/talos/talos/tests/scroll/reader.htm | 2 +- .../talos/tests/scroll/tiled-downscale.html | 2 +- .../tests/scroll/tiled-fixed-downscale.html | 2 +- .../talos/talos/tests/scroll/tiled-fixed.html | 2 +- testing/talos/talos/tests/scroll/tiled.html | 2 +- 7 files changed, 16 insertions(+), 18 deletions(-) diff --git a/testing/talos/talos/pageloader/chrome/tscroll.js b/testing/talos/talos/pageloader/chrome/tscroll.js index 232c32363326..3ef862bf20d0 100644 --- a/testing/talos/talos/pageloader/chrome/tscroll.js +++ b/testing/talos/talos/pageloader/chrome/tscroll.js @@ -1,9 +1,6 @@ -// Note: The content from here upto '// End scroll test' is duplicated at: -// - talos/tests/scroll/scroll-test.js -// - inside talos/pageloader/chrome/tscroll.js -// -// - Please keep these copies in sync. -// - Pleace make sure that any changes apply cleanly to all use cases. +// Note: This file is used at both tscrollx and tp5o_scroll. With the former as +// unprivileged code. +// - Please make sure that any changes apply cleanly to all use cases. function testScroll(target, stepSize, opt_reportFunc, opt_numSteps) { @@ -121,12 +118,13 @@ function testScroll(target, stepSize, opt_reportFunc, opt_numSteps) rAF(startTest); }, 260); } -// End scroll test - End duplicated code // This code below here is unique to tscroll.js inside of pageloader -function handleMessageFromChrome(message) { - var payload = message.data.details; - testScroll(payload.target, payload.stepSize, 'PageLoader:RecordTime', payload.opt_numSteps); -} +try { + function handleMessageFromChrome(message) { + var payload = message.data.details; + testScroll(payload.target, payload.stepSize, 'PageLoader:RecordTime', payload.opt_numSteps); + } -addMessageListener("PageLoader:ScrollTest", handleMessageFromChrome); + addMessageListener("PageLoader:ScrollTest", handleMessageFromChrome); +} catch (e) {} diff --git a/testing/talos/talos/tests/scroll/iframe.svg b/testing/talos/talos/tests/scroll/iframe.svg index 18948c400360..c9005d9ac07c 100644 --- a/testing/talos/talos/tests/scroll/iframe.svg +++ b/testing/talos/talos/tests/scroll/iframe.svg @@ -35,5 +35,5 @@ - + - + - - Test for Bug 918719 - - - - -Mozilla Bug 918719 -

- -
-
-
- - - diff --git a/dom/xhr/XMLHttpRequestMainThread.cpp b/dom/xhr/XMLHttpRequestMainThread.cpp index 24e98c91e432..496ee55c0937 100644 --- a/dom/xhr/XMLHttpRequestMainThread.cpp +++ b/dom/xhr/XMLHttpRequestMainThread.cpp @@ -169,7 +169,6 @@ XMLHttpRequestMainThread::XMLHttpRequestMainThread() mFlagSyncLooping(false), mFlagBackgroundRequest(false), mFlagHadUploadListenersOnSend(false), mFlagACwithCredentials(false), mFlagTimedOut(false), mFlagDeleted(false), mFlagSend(false), - mSendExtraLoadingEvents(Preferences::GetBool("dom.fire_extra_xhr_loading_readystatechanges", true)), mUploadTransferred(0), mUploadTotal(0), mUploadComplete(true), mProgressSinceLastProgressEvent(false), mRequestSentTime(0), mTimeoutMilliseconds(0), @@ -1715,9 +1714,7 @@ XMLHttpRequestMainThread::OnDataAvailable(nsIRequest *request, mDataAvailable += totalRead; - if (mState == State::headers_received || mSendExtraLoadingEvents) { - ChangeState(State::loading); - } + ChangeState(State::loading); if (!mFlagSynchronous && !mProgressTimerIsActive) { StartProgressEventTimer(); diff --git a/dom/xhr/XMLHttpRequestMainThread.h b/dom/xhr/XMLHttpRequestMainThread.h index 5bc686b26cf2..9fa711f66ff6 100644 --- a/dom/xhr/XMLHttpRequestMainThread.h +++ b/dom/xhr/XMLHttpRequestMainThread.h @@ -686,14 +686,6 @@ protected: // late, and ensure the XHR only handles one in-flight request at once. bool mFlagSend; - // Before ProgressEvents were a thing, multiple readystatechange events were - // fired during the loading state to give sites a way to monitor XHR progress. - // The XHR spec now has proper progress events and dictates that only one - // "loading" readystatechange should be fired per send. However, it's possible - // that some content still relies on this old behavior, so we're keeping it - // (behind a preference) for now. See bug 918719. - bool mSendExtraLoadingEvents; - RefPtr mUpload; int64_t mUploadTransferred; int64_t mUploadTotal; diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index cede4fa506b4..8591809abf18 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -5088,10 +5088,6 @@ pref("dom.voicemail.defaultServiceId", 0); // Enable mapped array buffer by default. pref("dom.mapped_arraybuffer.enabled", true); -// Whether to send more than one "loading" readystatechange during XHRs to -// simulate progress events for sites still not using modern progress events. -pref("dom.fire_extra_xhr_loading_readystatechanges", false); - // The tables used for Safebrowsing phishing and malware checks. pref("urlclassifier.malwareTable", "goog-malware-shavar,goog-unwanted-shavar,test-malware-simple,test-unwanted-simple"); diff --git a/testing/web-platform/meta/XMLHttpRequest/event-readystatechange-loaded.htm.ini b/testing/web-platform/meta/XMLHttpRequest/event-readystatechange-loaded.htm.ini new file mode 100644 index 000000000000..5cf0e5fade89 --- /dev/null +++ b/testing/web-platform/meta/XMLHttpRequest/event-readystatechange-loaded.htm.ini @@ -0,0 +1,5 @@ +[event-readystatechange-loaded.htm] + type: testharness + [XMLHttpRequest: the LOADING state change should only happen once] + expected: FAIL + From 865f4251ec2fa0a4a2cda4a3972e87b5330cb585 Mon Sep 17 00:00:00 2001 From: George Wright Date: Tue, 27 Sep 2016 16:10:02 -0400 Subject: [PATCH 066/102] Bug 1304360 - Add Windows 7 w/Intel drivers less than or equal to build ID 1749 to the blocklist for D3D9 layers r=milan --- widget/windows/GfxInfo.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/widget/windows/GfxInfo.cpp b/widget/windows/GfxInfo.cpp index d62b1b18a6ee..0041d364c942 100644 --- a/widget/windows/GfxInfo.cpp +++ b/widget/windows/GfxInfo.cpp @@ -1195,6 +1195,12 @@ GfxInfo::GetGfxDriverInfo() nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE, nsIGfxInfo::FEATURE_BLOCKED_DEVICE, DRIVER_LESS_THAN, GfxDriverInfo::allDriverVersions, "FEATURE_FAILURE_BUG_1153381"); + /* Bug 1304360: Graphical artifacts with D3D9 on Windows 7. */ + APPEND_TO_DRIVER_BLOCKLIST2(OperatingSystem::Windows7, + (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorIntel), (GfxDeviceFamily*)GfxDriverInfo::GetDeviceFamily(IntelGMAX3000), + nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, + DRIVER_BUILD_ID_LESS_THAN_OR_EQUAL, 1749, "FEATURE_FAILURE_INTEL_W7_D3D9_LAYERS"); + //////////////////////////////////// // WebGL From ea061497c38d6a588c1c69dd5683f23d0b869b70 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 27 Sep 2016 13:15:55 -0700 Subject: [PATCH 067/102] Fix vsync sometimes not firing after the GPU process crashes. (bug 1305628, r=mattwoodrow) --- gfx/ipc/RemoteCompositorSession.cpp | 1 + widget/nsBaseWidget.cpp | 16 +++++++++------- widget/windows/InProcessWinCompositorWidget.cpp | 5 +++-- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/gfx/ipc/RemoteCompositorSession.cpp b/gfx/ipc/RemoteCompositorSession.cpp index 0ccabaaa7ed8..8ebcc88e6f84 100644 --- a/gfx/ipc/RemoteCompositorSession.cpp +++ b/gfx/ipc/RemoteCompositorSession.cpp @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "RemoteCompositorSession.h" +#include "mozilla/VsyncDispatcher.h" #include "mozilla/layers/APZChild.h" #include "mozilla/layers/APZCTreeManagerChild.h" #include "nsBaseWidget.h" diff --git a/widget/nsBaseWidget.cpp b/widget/nsBaseWidget.cpp index 129cd91af61a..c5b5538cfa99 100644 --- a/widget/nsBaseWidget.cpp +++ b/widget/nsBaseWidget.cpp @@ -260,6 +260,15 @@ nsBaseWidget::Shutdown() void nsBaseWidget::DestroyCompositor() { + // We release this before releasing the compositor, since it may hold the + // last reference to our ClientLayerManager. ClientLayerManager's dtor can + // trigger a paint, creating a new compositor, and we don't want to re-use + // the old vsync dispatcher. + if (mCompositorVsyncDispatcher) { + mCompositorVsyncDispatcher->Shutdown(); + mCompositorVsyncDispatcher = nullptr; + } + // The compositor shutdown sequence looks like this: // 1. CompositorSession calls CompositorBridgeChild::Destroy. // 2. CompositorBridgeChild synchronously sends WillClose. @@ -284,13 +293,6 @@ void nsBaseWidget::DestroyCompositor() RefPtr session = mCompositorSession.forget(); session->Shutdown(); } - - // Can have base widgets that are things like tooltips - // which don't have CompositorVsyncDispatchers - if (mCompositorVsyncDispatcher) { - mCompositorVsyncDispatcher->Shutdown(); - mCompositorVsyncDispatcher = nullptr; - } } void nsBaseWidget::ReleaseContentController() diff --git a/widget/windows/InProcessWinCompositorWidget.cpp b/widget/windows/InProcessWinCompositorWidget.cpp index f88c94ac161d..685eaf5ca62c 100644 --- a/widget/windows/InProcessWinCompositorWidget.cpp +++ b/widget/windows/InProcessWinCompositorWidget.cpp @@ -32,8 +32,9 @@ InProcessWinCompositorWidget::RealWidget() void InProcessWinCompositorWidget::ObserveVsync(VsyncObserver* aObserver) { - RefPtr cvd = mWindow->GetCompositorVsyncDispatcher(); - cvd->SetCompositorVsyncObserver(aObserver); + if (RefPtr cvd = mWindow->GetCompositorVsyncDispatcher()) { + cvd->SetCompositorVsyncObserver(aObserver); + } } } // namespace widget From 9d11cb086818023760d0459c403c0f9de6f3d076 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Mon, 26 Sep 2016 10:19:07 -0700 Subject: [PATCH 068/102] Bug 1301301, part 3 - Implement Begin and EndCycleCollectionCallback in CCJSContext. r=smaug This will let my later patch run code at the start and end of each CC. This patch should not change any behavior. MozReview-Commit-ID: Fu6v3wo8qKB --- dom/workers/RuntimeService.cpp | 10 ---------- js/xpconnect/src/XPCJSContext.cpp | 2 ++ xpcom/base/CycleCollectedJSContext.cpp | 10 ++++++++++ xpcom/base/CycleCollectedJSContext.h | 4 ++-- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index cd7c0d18d7c1..f14177acab0f 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -1099,16 +1099,6 @@ public: { } - virtual void - BeginCycleCollectionCallback() override - { - } - - virtual void - EndCycleCollectionCallback(CycleCollectorResults &aResults) override - { - } - void DispatchDeferredDeletion(bool aContinuation, bool aPurge) override { diff --git a/js/xpconnect/src/XPCJSContext.cpp b/js/xpconnect/src/XPCJSContext.cpp index 909e54b8e028..1fbe657387b8 100644 --- a/js/xpconnect/src/XPCJSContext.cpp +++ b/js/xpconnect/src/XPCJSContext.cpp @@ -665,6 +665,7 @@ XPCJSContext::PrepareForForgetSkippable() void XPCJSContext::BeginCycleCollectionCallback() { + CycleCollectedJSContext::BeginCycleCollectionCallback(); nsJSContext::BeginCycleCollectionCallback(); nsCOMPtr obs = mozilla::services::GetObserverService(); @@ -676,6 +677,7 @@ XPCJSContext::BeginCycleCollectionCallback() void XPCJSContext::EndCycleCollectionCallback(CycleCollectorResults& aResults) { + CycleCollectedJSContext::EndCycleCollectionCallback(aResults); nsJSContext::EndCycleCollectionCallback(aResults); nsCOMPtr obs = mozilla::services::GetObserverService(); diff --git a/xpcom/base/CycleCollectedJSContext.cpp b/xpcom/base/CycleCollectedJSContext.cpp index 93b0dc3d839f..b0b4347685b6 100644 --- a/xpcom/base/CycleCollectedJSContext.cpp +++ b/xpcom/base/CycleCollectedJSContext.cpp @@ -1330,6 +1330,16 @@ CycleCollectedJSContext::DumpJSHeap(FILE* aFile) js::DumpHeap(Context(), aFile, js::CollectNurseryBeforeDump); } +void +CycleCollectedJSContext::BeginCycleCollectionCallback() +{ +} + +void +CycleCollectedJSContext::EndCycleCollectionCallback(CycleCollectorResults& aResults) +{ +} + void CycleCollectedJSContext::ProcessStableStateQueue() { diff --git a/xpcom/base/CycleCollectedJSContext.h b/xpcom/base/CycleCollectedJSContext.h index 9415634b8951..130734b44969 100644 --- a/xpcom/base/CycleCollectedJSContext.h +++ b/xpcom/base/CycleCollectedJSContext.h @@ -321,8 +321,8 @@ public: void DumpJSHeap(FILE* aFile); virtual void PrepareForForgetSkippable() = 0; - virtual void BeginCycleCollectionCallback() = 0; - virtual void EndCycleCollectionCallback(CycleCollectorResults& aResults) = 0; + virtual void BeginCycleCollectionCallback(); + virtual void EndCycleCollectionCallback(CycleCollectorResults& aResults); virtual void DispatchDeferredDeletion(bool aContinuation, bool aPurge = false) = 0; JSContext* Context() const From 5a97b708ad5e385909e3649e697d4308258967bc Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Mon, 26 Sep 2016 10:19:07 -0700 Subject: [PATCH 069/102] Bug 1301301, part 4 - Make calls to JS::TraceChildren go through a single method on CCJSContext. r=smaug In this patch I add a new tracer base class, CCJSTracer, and make all of the code in CycleCollectedJSContext that used to do JS::TraceChildren depend on it. This will let me record the number of calls to JS::TraceChildren in one place, in a later patch. This should not change any behavior. MozReview-Commit-ID: LdDu5rnpvX0 --- xpcom/base/CycleCollectedJSContext.cpp | 62 ++++++++++++++++++-------- xpcom/base/CycleCollectedJSContext.h | 4 +- 2 files changed, 47 insertions(+), 19 deletions(-) diff --git a/xpcom/base/CycleCollectedJSContext.cpp b/xpcom/base/CycleCollectedJSContext.cpp index b0b4347685b6..fe77801cb286 100644 --- a/xpcom/base/CycleCollectedJSContext.cpp +++ b/xpcom/base/CycleCollectedJSContext.cpp @@ -127,11 +127,29 @@ public: } // namespace mozilla -struct NoteWeakMapChildrenTracer : public JS::CallbackTracer +struct CCJSTracer : public JS::CallbackTracer { - NoteWeakMapChildrenTracer(JSContext* aCx, +protected: + CCJSTracer(CycleCollectedJSContext* aCx, + WeakMapTraceKind aWeakTraceKind = TraceWeakMapValues) + : JS::CallbackTracer(aCx->Context(), aWeakTraceKind) + , mCx(aCx) + {} + +public: + void TraceChildren(JS::GCCellPtr aThing) + { + mCx->TraceJSChildren(this, aThing); + } + + CycleCollectedJSContext* mCx; +}; + +struct NoteWeakMapChildrenTracer : public CCJSTracer +{ + NoteWeakMapChildrenTracer(CycleCollectedJSContext* aCx, nsCycleCollectionNoteRootCallback& aCb) - : JS::CallbackTracer(aCx), mCb(aCb), mTracedAny(false), mMap(nullptr), + : CCJSTracer(aCx), mCb(aCb), mTracedAny(false), mMap(nullptr), mKey(nullptr), mKeyDelegate(nullptr) { } @@ -158,14 +176,15 @@ NoteWeakMapChildrenTracer::onChild(const JS::GCCellPtr& aThing) mCb.NoteWeakMapping(mMap, mKey, mKeyDelegate, aThing); mTracedAny = true; } else { - JS::TraceChildren(this, aThing); + TraceChildren(aThing); } } struct NoteWeakMapsTracer : public js::WeakMapTracer { - NoteWeakMapsTracer(JSContext* aCx, nsCycleCollectionNoteRootCallback& aCccb) - : js::WeakMapTracer(aCx), mCb(aCccb), mChildTracer(aCx, aCccb) + NoteWeakMapsTracer(CycleCollectedJSContext* aCx, + nsCycleCollectionNoteRootCallback& aCccb) + : js::WeakMapTracer(aCx->Context()), mCb(aCccb), mChildTracer(aCx, aCccb) { } void trace(JSObject* aMap, JS::GCCellPtr aKey, JS::GCCellPtr aValue) override; @@ -213,7 +232,7 @@ NoteWeakMapsTracer::trace(JSObject* aMap, JS::GCCellPtr aKey, mChildTracer.mKeyDelegate = kdelegate; if (!aValue.is()) { - JS::TraceChildren(&mChildTracer, aValue); + mChildTracer.TraceChildren(aValue); } // The delegate could hold alive the key, so report something to the CC @@ -324,12 +343,13 @@ JSZoneParticipant::Traverse(void* aPtr, nsCycleCollectionTraversalCallback& aCb) return NS_OK; } -struct TraversalTracer : public JS::CallbackTracer +struct TraversalTracer : public CCJSTracer { - TraversalTracer(JSContext* aCx, nsCycleCollectionTraversalCallback& aCb) - : JS::CallbackTracer(aCx, DoNotTraceWeakMaps), mCb(aCb) - { - } + TraversalTracer(CycleCollectedJSContext* aCx, + nsCycleCollectionTraversalCallback& aCb) + : CCJSTracer(aCx, DoNotTraceWeakMaps) + , mCb(aCb) + {} void onChild(const JS::GCCellPtr& aThing) override; nsCycleCollectionTraversalCallback& mCb; }; @@ -366,7 +386,7 @@ TraversalTracer::onChild(const JS::GCCellPtr& aThing) // be traced. JS_TraceObjectGroupCycleCollectorChildren(this, aThing); } else if (!aThing.is()) { - JS::TraceChildren(this, aThing); + TraceChildren(aThing); } } @@ -630,11 +650,11 @@ CycleCollectedJSContext::DescribeGCThing(bool aIsMarked, JS::GCCellPtr aThing, void CycleCollectedJSContext::NoteGCThingJSChildren(JS::GCCellPtr aThing, - nsCycleCollectionTraversalCallback& aCb) const + nsCycleCollectionTraversalCallback& aCb) { MOZ_ASSERT(mJSContext); - TraversalTracer trc(mJSContext, aCb); - JS::TraceChildren(&trc, aThing); + TraversalTracer trc(this, aCb); + trc.TraceChildren(aThing); } void @@ -733,7 +753,7 @@ CycleCollectedJSContext::TraverseZone(JS::Zone* aZone, * iterate over. Edges between compartments in the same zone will add * unnecessary loop edges to the graph (bug 842137). */ - TraversalTracer trc(mJSContext, aCb); + TraversalTracer trc(this, aCb); js::VisitGrayWrapperTargets(aZone, NoteJSChildGrayWrapperShim, &trc); /* @@ -1212,7 +1232,7 @@ CycleCollectedJSContext::TraverseRoots(nsCycleCollectionNoteRootCallback& aCb) TraverseNativeRoots(aCb); - NoteWeakMapsTracer trc(mJSContext, aCb); + NoteWeakMapsTracer trc(this, aCb); js::TraceWeakMaps(&trc); return NS_OK; @@ -1679,6 +1699,12 @@ CycleCollectedJSContext::OnLargeAllocationFailure() AnnotateAndSetOutOfMemory(&mLargeAllocationFailureState, OOMState::Reported); } +void +CycleCollectedJSContext::TraceJSChildren(JSTracer* aTrc, JS::GCCellPtr aThing) +{ + JS::TraceChildren(aTrc, aThing); +} + void CycleCollectedJSContext::PrepareWaitingZonesForGC() { diff --git a/xpcom/base/CycleCollectedJSContext.h b/xpcom/base/CycleCollectedJSContext.h index 130734b44969..6299624b14a1 100644 --- a/xpcom/base/CycleCollectedJSContext.h +++ b/xpcom/base/CycleCollectedJSContext.h @@ -176,7 +176,7 @@ private: void NoteGCThingJSChildren(JS::GCCellPtr aThing, - nsCycleCollectionTraversalCallback& aCb) const; + nsCycleCollectionTraversalCallback& aCb); void NoteGCThingXPCOMChildren(const js::Class* aClasp, JSObject* aObj, @@ -395,6 +395,8 @@ public: mZonesWaitingForGC.PutEntry(aZone); } + void TraceJSChildren(JSTracer* aTrc, JS::GCCellPtr aThing); + // Prepare any zones for GC that have been passed to AddZoneWaitingForGC() // since the last GC or since the last call to PrepareWaitingZonesForGC(), // whichever was most recent. If there were no such zones, prepare for a From 068861044a4e730a6db6229ee0f1eeae4705ca74 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Mon, 26 Sep 2016 10:19:07 -0700 Subject: [PATCH 070/102] Bug 1301301, part 5 - In debug builds, check if there are too many calls to JS::TraceChildren. r=smaug This can indicate that we are repeatedly calling TraceChildren on non-AddToCCKind GC things. MozReview-Commit-ID: C2udI1zg5R9 --- xpcom/base/CycleCollectedJSContext.cpp | 35 ++++++++++++++++++++++++++ xpcom/base/CycleCollectedJSContext.h | 5 ++++ 2 files changed, 40 insertions(+) diff --git a/xpcom/base/CycleCollectedJSContext.cpp b/xpcom/base/CycleCollectedJSContext.cpp index fe77801cb286..b5f4a13230ca 100644 --- a/xpcom/base/CycleCollectedJSContext.cpp +++ b/xpcom/base/CycleCollectedJSContext.cpp @@ -462,6 +462,10 @@ CycleCollectedJSContext::CycleCollectedJSContext() , mDisableMicroTaskCheckpoint(false) , mOutOfMemoryState(OOMState::OK) , mLargeAllocationFailureState(OOMState::OK) +#ifdef DEBUG + , mNumTraversedGCThings(0) + , mNumTraceChildren(0) +#endif // DEBUG { nsCOMPtr thread = do_GetCurrentThread(); mOwningThread = thread.forget().downcast().take(); @@ -711,6 +715,10 @@ CycleCollectedJSContext::TraverseGCThing(TraverseSelect aTs, JS::GCCellPtr aThin return; } +#ifdef DEBUG + ++mNumTraversedGCThings; +#endif + if (aTs == TRAVERSE_FULL) { NoteGCThingJSChildren(aThing, aCb); } @@ -1353,11 +1361,35 @@ CycleCollectedJSContext::DumpJSHeap(FILE* aFile) void CycleCollectedJSContext::BeginCycleCollectionCallback() { +#ifdef DEBUG + mNumTraversedGCThings = 0; + mNumTraceChildren = 0; +#endif } void CycleCollectedJSContext::EndCycleCollectionCallback(CycleCollectorResults& aResults) { +#ifdef DEBUG + + // GC things that the cycle collector calls Traverse on (ie things + // in the CC graph) will also get JS::TraceChildren() called on + // them. If a child of a GC thing in the CC graph does not have an + // AddToCCKind(), then the CC calls JS::TraceChildren() on it + // without adding it to the graph. If there are many such objects + // that are referred to by many objects in the CC graph, then the CC + // can spend a lot of time in JS::TraceChildren(). If you add a new + // TraceKind and are hitting this assertion, adding it to + // AddToCCKind might help. (The check is not done for small CC + // graphs to avoid noise.) + if (mNumTraceChildren > 1000 && mNumTraversedGCThings > 0) { + double traceRatio = ((double)mNumTraceChildren) / ((double)mNumTraversedGCThings); + MOZ_ASSERT(traceRatio < 2.2, "Excessive calls to JS::TraceChildren by the cycle collector"); + } + + mNumTraversedGCThings = 0; + mNumTraceChildren = 0; +#endif } void @@ -1702,6 +1734,9 @@ CycleCollectedJSContext::OnLargeAllocationFailure() void CycleCollectedJSContext::TraceJSChildren(JSTracer* aTrc, JS::GCCellPtr aThing) { +#ifdef DEBUG + ++mNumTraceChildren; +#endif // DEBUG JS::TraceChildren(aTrc, aThing); } diff --git a/xpcom/base/CycleCollectedJSContext.h b/xpcom/base/CycleCollectedJSContext.h index 6299624b14a1..5cc0026d214b 100644 --- a/xpcom/base/CycleCollectedJSContext.h +++ b/xpcom/base/CycleCollectedJSContext.h @@ -478,6 +478,11 @@ private: void invoke(JS::HandleObject scope, Closure& closure) override; }; EnvironmentPreparer mEnvironmentPreparer; + +#ifdef DEBUG + uint32_t mNumTraversedGCThings; + uint32_t mNumTraceChildren; +#endif // DEBUG }; void TraceScriptHolder(nsISupports* aHolder, JSTracer* aTracer); From 06e9d640a1fa22e33416a4a26264c59bd82375b2 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Fri, 23 Sep 2016 02:25:01 -0700 Subject: [PATCH 071/102] Bug 1269722 - Make GenericPrinter::put return < 0 *only* when an error is reported, and don't attempt to support partial puts. r=jandem --HG-- extra : rebase_source : f1ff2667364150acadd05fb816e0faeef0aa0845 --- js/src/vm/Printer.cpp | 103 ++++++++++++++++++++++++------------------ 1 file changed, 60 insertions(+), 43 deletions(-) diff --git a/js/src/vm/Printer.cpp b/js/src/vm/Printer.cpp index d72fbfebf9d1..61166837b7f5 100644 --- a/js/src/vm/Printer.cpp +++ b/js/src/vm/Printer.cpp @@ -6,6 +6,8 @@ #include "vm/Printer.h" +#include "mozilla/PodOperations.h" + #include #include #include @@ -16,6 +18,8 @@ #include "ds/LifoAlloc.h" +using mozilla::PodCopy; + namespace js { GenericPrinter::GenericPrinter() @@ -238,7 +242,7 @@ Sprinter::putString(JSString* s) JS::AutoCheckCannotGC nogc; if (linear->hasLatin1Chars()) - mozilla::PodCopy(reinterpret_cast(buffer), linear->latin1Chars(nogc), length); + PodCopy(reinterpret_cast(buffer), linear->latin1Chars(nogc), length); else DeflateStringToBuffer(nullptr, linear->twoByteChars(nogc), length, buffer, &size); @@ -442,19 +446,17 @@ Fprinter::put(const char* s, size_t len) { MOZ_ASSERT(file_); int i = fwrite(s, len, 1, file_); - if (i == -1 || i != int(len)) + if (size_t(i) != len) { reportOutOfMemory(); + return -1; + } return i; } int Fprinter::put(const char* s) { - MOZ_ASSERT(file_); - int i = fputs(s, file_); - if (i == -1) - reportOutOfMemory(); - return i; + return put(s, strlen(s)); } int @@ -516,53 +518,68 @@ LSprinter::clear() int LSprinter::put(const char* s, size_t len) { - size_t origLen = len; + // Compute how much data will fit in the current chunk. + size_t existingSpaceWrite = 0; + size_t overflow = len; if (unused_ > 0 && tail_) { - size_t minLen = unused_ < len ? unused_ : len; - js_memcpy(tail_->end() - unused_, s, minLen); - unused_ -= minLen; - len -= minLen; - s += minLen; + existingSpaceWrite = std::min(unused_, len); + overflow = len - existingSpaceWrite; } - if (len == 0) - return origLen; - - size_t allocLength = AlignBytes(sizeof(Chunk) + len, js::detail::LIFO_ALLOC_ALIGN); + // If necessary, allocate a new chunk for overflow data. + size_t allocLength = 0; Chunk* last = nullptr; - { + if (overflow > 0) { + allocLength = AlignBytes(sizeof(Chunk) + overflow, js::detail::LIFO_ALLOC_ALIGN); + LifoAlloc::AutoFallibleScope fallibleAllocator(alloc_); last = reinterpret_cast(alloc_->alloc(allocLength)); - } - if (!last) { - reportOutOfMemory(); - return origLen - len; + if (!last) { + reportOutOfMemory(); + return -1; + } } - if (tail_ && reinterpret_cast(last) == tail_->end()) { - // tail_ and last are next to each others in memory, knowing that the - // TempAlloctator has no meta data and is just a bump allocator, we - // append the new allocated space to the tail_. - unused_ = allocLength; - tail_->length += allocLength; - } else { - // Remove the size of the header from the allocated length. - allocLength -= sizeof(Chunk); - last->next = nullptr; - last->length = allocLength; - unused_ = allocLength; - if (!head_) - head_ = last; - else - tail_->next = last; + // All fallible operations complete: now fill up existing space, then + // overflow space in any new chunk. + MOZ_ASSERT(existingSpaceWrite + overflow == len); - tail_ = last; + if (existingSpaceWrite > 0) { + PodCopy(tail_->end() - unused_, s, existingSpaceWrite); + unused_ -= existingSpaceWrite; + s += existingSpaceWrite; } - MOZ_ASSERT(tail_->length >= unused_); - js_memcpy(tail_->end() - unused_, s, len); - unused_ -= len; - return origLen; + if (overflow > 0) { + if (tail_ && reinterpret_cast(last) == tail_->end()) { + // tail_ and last are consecutive in memory. LifoAlloc has no + // metadata and is just a bump allocator, so we can cheat by + // appending the newly-allocated space to tail_. + unused_ = allocLength; + tail_->length += allocLength; + } else { + // Remove the size of the header from the allocated length. + size_t availableSpace = allocLength - sizeof(Chunk); + last->next = nullptr; + last->length = availableSpace; + + unused_ = availableSpace; + if (!head_) + head_ = last; + else + tail_->next = last; + + tail_ = last; + } + + PodCopy(tail_->end() - unused_, s, overflow); + + MOZ_ASSERT(unused_ >= overflow); + unused_ -= overflow; + } + + MOZ_ASSERT(len <= INT_MAX); + return int(len); } int From e600ef69d7a173245aa739952e3b7368a86eadfd Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Fri, 23 Sep 2016 02:25:06 -0700 Subject: [PATCH 072/102] Bug 1269722 - Make GenericPrinter::put(const char*) inline, delegating to the length-delimited put(), as its algorithm is now identical everywhere. r=jandem --HG-- extra : rebase_source : 0e36601b8812c9862ddaf36d1259ce5e22808cc7 --- js/src/vm/Printer.cpp | 18 ------------------ js/src/vm/Printer.h | 11 +++++++---- 2 files changed, 7 insertions(+), 22 deletions(-) diff --git a/js/src/vm/Printer.cpp b/js/src/vm/Printer.cpp index 61166837b7f5..54cb939e689a 100644 --- a/js/src/vm/Printer.cpp +++ b/js/src/vm/Printer.cpp @@ -41,12 +41,6 @@ GenericPrinter::hadOutOfMemory() const return hadOOM_; } -int -GenericPrinter::put(const char* s) -{ - return put(s, strlen(s)); -} - int GenericPrinter::printf(const char* fmt, ...) { @@ -453,12 +447,6 @@ Fprinter::put(const char* s, size_t len) return i; } -int -Fprinter::put(const char* s) -{ - return put(s, strlen(s)); -} - int Fprinter::printf(const char* fmt, ...) { @@ -582,12 +570,6 @@ LSprinter::put(const char* s, size_t len) return int(len); } -int -LSprinter::put(const char* s) -{ - return put(s, strlen(s)); -} - int LSprinter::printf(const char* fmt, ...) { diff --git a/js/src/vm/Printer.h b/js/src/vm/Printer.h index c8aa43f268ef..b64a81aa5987 100644 --- a/js/src/vm/Printer.h +++ b/js/src/vm/Printer.h @@ -36,7 +36,10 @@ class GenericPrinter // Puts |len| characters from |s| at the current position and return an offset to // the beginning of this new data. virtual int put(const char* s, size_t len) = 0; - virtual int put(const char* s); + + inline int put(const char* s) { + return put(s, strlen(s)); + } // Prints a formatted string into the buffer. virtual int printf(const char* fmt, ...); @@ -105,8 +108,8 @@ class Sprinter final : public GenericPrinter // Puts |len| characters from |s| at the current position and return an offset to // the beginning of this new data. - using GenericPrinter::put; virtual int put(const char* s, size_t len) override; + using GenericPrinter::put; // pick up |inline int put(const char* s);| // Prints a formatted string into the buffer. virtual int vprintf(const char* fmt, va_list ap) override; @@ -145,7 +148,7 @@ class Fprinter final : public GenericPrinter // Puts |len| characters from |s| at the current position and return an // offset to the beginning of this new data. virtual int put(const char* s, size_t len) override; - virtual int put(const char* s) override; + using GenericPrinter::put; // pick up |inline int put(const char* s);| // Prints a formatted string into the buffer. virtual int printf(const char* fmt, ...) override; @@ -191,7 +194,7 @@ class LSprinter final : public GenericPrinter // Puts |len| characters from |s| at the current position and return an // offset to the beginning of this new data. virtual int put(const char* s, size_t len) override; - virtual int put(const char* s) override; + using GenericPrinter::put; // pick up |inline int put(const char* s);| // Prints a formatted string into the buffer. virtual int printf(const char* fmt, ...) override; From 1627aee084ef6c9298894c5b987ff27067c5776a Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Fri, 23 Sep 2016 19:20:31 -0700 Subject: [PATCH 073/102] Bug 1269722 - Remove the standalone Sprint function that almost no one error-checks in favor of a member function, and error-check every use of it. r=jandem --HG-- extra : rebase_source : 21506b36159c77148510dae70bb584a526828196 --- js/src/jsopcode.cpp | 221 +++++++++++++--------- js/src/jsopcode.h | 15 +- js/src/shell/js.cpp | 422 ++++++++++++++++++++++++++++-------------- js/src/vm/Printer.cpp | 43 +++-- js/src/vm/Printer.h | 8 +- 5 files changed, 448 insertions(+), 261 deletions(-) diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 229aec9fe715..63a77d9ba566 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -12,6 +12,7 @@ #define __STDC_FORMAT_MACROS +#include "mozilla/Attributes.h" #include "mozilla/SizePrintfMacros.h" #include "mozilla/Sprintf.h" @@ -147,28 +148,40 @@ js::StackDefs(JSScript* script, jsbytecode* pc) const char * PCCounts::numExecName = "interp"; -void -js::DumpIonScriptCounts(Sprinter* sp, HandleScript script, - jit::IonScriptCounts* ionCounts) +static MOZ_MUST_USE bool +DumpIonScriptCounts(Sprinter* sp, HandleScript script, jit::IonScriptCounts* ionCounts) { - Sprint(sp, "IonScript [%lu blocks]:\n", ionCounts->numBlocks()); + if (!sp->jsprintf("IonScript [%lu blocks]:\n", ionCounts->numBlocks())) + return false; + for (size_t i = 0; i < ionCounts->numBlocks(); i++) { const jit::IonBlockCounts& block = ionCounts->block(i); unsigned lineNumber = 0, columnNumber = 0; lineNumber = PCToLineNumber(script, script->offsetToPC(block.offset()), &columnNumber); - Sprint(sp, "BB #%lu [%05u,%u,%u]", block.id(), block.offset(), - lineNumber, columnNumber); - if (block.description()) - Sprint(sp, " [inlined %s]", block.description()); - for (size_t j = 0; j < block.numSuccessors(); j++) - Sprint(sp, " -> #%lu", block.successor(j)); - Sprint(sp, " :: %llu hits\n", block.hitCount()); - Sprint(sp, "%s\n", block.code()); + if (!sp->jsprintf("BB #%lu [%05u,%u,%u]", + block.id(), block.offset(), lineNumber, columnNumber)) + { + return false; + } + if (block.description()) { + if (!sp->jsprintf(" [inlined %s]", block.description())) + return false; + } + for (size_t j = 0; j < block.numSuccessors(); j++) { + if (!sp->jsprintf(" -> #%lu", block.successor(j))) + return false; + } + if (!sp->jsprintf(" :: %llu hits\n", block.hitCount())) + return false; + if (!sp->jsprintf("%s\n", block.code())) + return false; } + + return true; } -void -js::DumpPCCounts(JSContext* cx, HandleScript script, Sprinter* sp) +static MOZ_MUST_USE bool +DumpPCCounts(JSContext* cx, HandleScript script, Sprinter* sp) { MOZ_ASSERT(script->hasScriptCounts()); @@ -178,28 +191,35 @@ js::DumpPCCounts(JSContext* cx, HandleScript script, Sprinter* sp) jsbytecode* next = GetNextPc(pc); if (!Disassemble1(cx, script, pc, script->pcToOffset(pc), true, sp)) - return; + return false; + + if (sp->put(" {") < 0) + return false; - Sprint(sp, " {"); PCCounts* counts = script->maybeGetPCCounts(pc); - double val = counts ? counts->numExec() : 0.0; - if (val) - Sprint(sp, "\"%s\": %.0f", PCCounts::numExecName, val); - Sprint(sp, "}\n"); + if (double val = counts ? counts->numExec() : 0.0) { + if (!sp->jsprintf("\"%s\": %.0f", PCCounts::numExecName, val)) + return false; + } + if (sp->put("}\n") < 0) + return false; pc = next; } #endif jit::IonScriptCounts* ionCounts = script->getIonCounts(); - while (ionCounts) { - DumpIonScriptCounts(sp, script, ionCounts); + if (!DumpIonScriptCounts(sp, script, ionCounts)) + return false; + ionCounts = ionCounts->previous(); } + + return true; } -void +bool js::DumpCompartmentPCCounts(JSContext* cx) { Rooted> scripts(cx, GCVector(cx)); @@ -207,21 +227,26 @@ js::DumpCompartmentPCCounts(JSContext* cx) JSScript* script = iter; if (script->compartment() != cx->compartment()) continue; - if (script->hasScriptCounts() && !scripts.append(script)) - return; + if (script->hasScriptCounts()) { + if (!scripts.append(script)) + return false; + } } for (uint32_t i = 0; i < scripts.length(); i++) { HandleScript script = scripts[i]; Sprinter sprinter(cx); if (!sprinter.init()) - return; + return false; fprintf(stdout, "--- SCRIPT %s:%" PRIuSIZE " ---\n", script->filename(), script->lineno()); - DumpPCCounts(cx, script, &sprinter); + if (!DumpPCCounts(cx, script, &sprinter)) + return false; fputs(sprinter.string(), stdout); fprintf(stdout, "--- END SCRIPT %s:%" PRIuSIZE " ---\n", script->filename(), script->lineno()); } + + return true; } ///////////////////////////////////////////////////////////////////// @@ -642,47 +667,65 @@ js::ReconstructStackDepth(JSContext* cx, JSScript* script, jsbytecode* pc, uint3 * current line. If showAll is true, include the source note type and the * entry stack depth. */ -static bool +static MOZ_MUST_USE bool DisassembleAtPC(JSContext* cx, JSScript* scriptArg, bool lines, jsbytecode* pc, bool showAll, Sprinter* sp) { RootedScript script(cx, scriptArg); BytecodeParser parser(cx, script); - if (showAll && !parser.parse()) + if (showAll) { + if (!parser.parse()) + return false; + + if (!sp->jsprintf("%s:%u\n", script->filename(), unsigned(script->lineno()))) + return false; + } + + if (pc != nullptr) { + if (sp->put(" ") < 0) + return false; + } + if (showAll) { + if (sp->put("sn stack ") < 0) + return false; + } + if (sp->put("loc ") < 0) + return false; + if (lines) { + if (sp->put("line") < 0) + return false; + } + if (sp->put(" op\n") < 0) return false; - if (showAll) - Sprint(sp, "%s:%" PRIuSIZE "\n", script->filename(), script->lineno()); - - if (pc != nullptr) - sp->put(" "); - if (showAll) - sp->put("sn stack "); - sp->put("loc "); - if (lines) - sp->put("line"); - sp->put(" op\n"); - - if (pc != nullptr) - sp->put(" "); - if (showAll) - sp->put("-- ----- "); - sp->put("----- "); - if (lines) - sp->put("----"); - sp->put(" --\n"); + if (pc != nullptr) { + if (sp->put(" ") < 0) + return false; + } + if (showAll) { + if (sp->put("-- ----- ") < 0) + return false; + } + if (sp->put("----- ") < 0) + return false; + if (lines) { + if (sp->put("----") < 0) + return false; + } + if (sp->put(" --\n") < 0) + return false; jsbytecode* next = script->code(); jsbytecode* end = script->codeEnd(); while (next < end) { - if (next == script->main()) - sp->put("main:\n"); + if (next == script->main()) { + if (sp->put("main:\n") < 0) + return false; + } if (pc != nullptr) { - if (pc == next) - sp->put("--> "); - else - sp->put(" "); + if (sp->put(pc == next ? "--> " : " ") < 0) + return false; } if (showAll) { jssrcnote* sn = GetSrcNote(cx, script, next); @@ -690,24 +733,32 @@ DisassembleAtPC(JSContext* cx, JSScript* scriptArg, bool lines, MOZ_ASSERT(!SN_IS_TERMINATOR(sn)); jssrcnote* next = SN_NEXT(sn); while (!SN_IS_TERMINATOR(next) && SN_DELTA(next) == 0) { - Sprint(sp, "%02u\n ", SN_TYPE(sn)); + if (!sp->jsprintf("%02u\n ", SN_TYPE(sn))) + return false; sn = next; next = SN_NEXT(sn); } - Sprint(sp, "%02u ", SN_TYPE(sn)); + if (!sp->jsprintf("%02u ", SN_TYPE(sn))) + return false; + } else { + if (sp->put(" ") < 0) + return false; + } + if (parser.isReachable(next)) { + if (!sp->jsprintf("%05u ", parser.stackDepthAtPC(next))) + return false; + } else { + if (sp->put(" ") < 0) + return false; } - else - sp->put(" "); - if (parser.isReachable(next)) - Sprint(sp, "%05u ", parser.stackDepthAtPC(next)); - else - Sprint(sp, " "); } unsigned len = Disassemble1(cx, script, next, script->pcToOffset(next), lines, sp); if (!len) return false; + next += len; } + return true; } @@ -886,11 +937,13 @@ js::Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc, } const JSCodeSpec* cs = &CodeSpec[op]; ptrdiff_t len = (ptrdiff_t) cs->length; - if (Sprint(sp, "%05u:", loc) == -1) + if (!sp->jsprintf("%05u:", loc)) return 0; - if (lines && Sprint(sp, "%4u", PCToLineNumber(script, pc)) == -1) - return 0; - if (Sprint(sp, " %s", CodeName[op]) == -1) + if (lines) { + if (!sp->jsprintf("%4u", PCToLineNumber(script, pc))) + return 0; + } + if (!sp->jsprintf(" %s", CodeName[op])) return 0; int i; @@ -906,9 +959,9 @@ js::Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc, for(i = 0; i < trynotes->length; i++) { JSTryNote note = trynotes->vector[i]; if (note.kind == JSTRY_CATCH && note.start == loc + 1) { - if (Sprint(sp, " %u (%+d)", - (unsigned int) (loc+note.length+1), - (int) (note.length+1)) == -1) + if (!sp->jsprintf(" %u (%+d)", + unsigned(loc + note.length + 1), + int(note.length + 1))) { return 0; } @@ -920,7 +973,7 @@ js::Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc, case JOF_JUMP: { ptrdiff_t off = GET_JUMP_OFFSET(pc); - if (Sprint(sp, " %u (%+d)", loc + (int) off, (int) off) == -1) + if (!sp->jsprintf(" %u (%+d)", unsigned(loc + int(off)), int(off))) return 0; break; } @@ -930,7 +983,7 @@ js::Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc, JSAutoByteString bytes; if (!ToDisassemblySource(cx, scope, &bytes)) return 0; - if (Sprint(sp, " %s", bytes.ptr()) == -1) + if (!sp->jsprintf(" %s", bytes.ptr())) return 0; break; } @@ -942,7 +995,7 @@ js::Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc, if (!ToDisassemblySource(cx, v, &bytes)) return 0; EnvironmentCoordinate ec(pc); - if (Sprint(sp, " %s (hops = %u, slot = %u)", bytes.ptr(), ec.hops(), ec.slot()) == -1) + if (!sp->jsprintf(" %s (hops = %u, slot = %u)", bytes.ptr(), ec.hops(), ec.slot())) return 0; break; } @@ -952,7 +1005,7 @@ js::Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc, JSAutoByteString bytes; if (!ToDisassemblySource(cx, v, &bytes)) return 0; - if (Sprint(sp, " %s", bytes.ptr()) == -1) + if (!sp->jsprintf(" %s", bytes.ptr())) return 0; break; } @@ -962,7 +1015,7 @@ js::Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc, JSAutoByteString bytes; if (!ToDisassemblySource(cx, v, &bytes)) return 0; - if (Sprint(sp, " %s", bytes.ptr()) == -1) + if (!sp->jsprintf(" %s", bytes.ptr())) return 0; break; } @@ -970,7 +1023,7 @@ js::Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc, case JOF_OBJECT: { /* Don't call obj.toSource if analysis/inference is active. */ if (script->zone()->types.activeAnalysis) { - if (Sprint(sp, " object") == -1) + if (!sp->jsprintf(" object")) return 0; break; } @@ -981,7 +1034,7 @@ js::Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc, RootedValue v(cx, ObjectValue(*obj)); if (!ToDisassemblySource(cx, v, &bytes)) return 0; - if (Sprint(sp, " %s", bytes.ptr()) == -1) + if (!sp->jsprintf(" %s", bytes.ptr())) return 0; } break; @@ -993,7 +1046,7 @@ js::Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc, RootedValue v(cx, ObjectValue(*obj)); if (!ToDisassemblySource(cx, v, &bytes)) return 0; - if (Sprint(sp, " %s", bytes.ptr()) == -1) + if (!sp->jsprintf(" %s", bytes.ptr())) return 0; break; } @@ -1008,11 +1061,11 @@ js::Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc, pc2 += JUMP_OFFSET_LEN; high = GET_JUMP_OFFSET(pc2); pc2 += JUMP_OFFSET_LEN; - if (Sprint(sp, " defaultOffset %d low %d high %d", int(off), low, high) == -1) + if (!sp->jsprintf(" defaultOffset %d low %d high %d", int(off), low, high)) return 0; for (i = low; i <= high; i++) { off = GET_JUMP_OFFSET(pc2); - if (Sprint(sp, "\n\t%d: %d", i, int(off)) == -1) + if (!sp->jsprintf("\n\t%d: %d", i, int(off))) return 0; pc2 += JUMP_OFFSET_LEN; } @@ -1021,17 +1074,17 @@ js::Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc, } case JOF_QARG: - if (Sprint(sp, " %u", GET_ARGNO(pc)) == -1) + if (!sp->jsprintf(" %u", GET_ARGNO(pc))) return 0; break; case JOF_LOCAL: - if (Sprint(sp, " %u", GET_LOCALNO(pc)) == -1) + if (!sp->jsprintf(" %u", GET_LOCALNO(pc))) return 0; break; case JOF_UINT32: - if (Sprint(sp, " %u", GET_UINT32(pc)) == -1) + if (!sp->jsprintf(" %u", GET_UINT32(pc))) return 0; break; @@ -1056,7 +1109,7 @@ js::Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc, MOZ_ASSERT(op == JSOP_INT32); i = GET_INT32(pc); print_int: - if (Sprint(sp, " %d", i) == -1) + if (!sp->jsprintf(" %d", i)) return 0; break; diff --git a/js/src/jsopcode.h b/js/src/jsopcode.h index dbeb6a03d209..4f78596656ab 100644 --- a/js/src/jsopcode.h +++ b/js/src/jsopcode.h @@ -11,6 +11,8 @@ * JS bytecode definitions. */ +#include "mozilla/Attributes.h" + #include "jsbytecode.h" #include "jstypes.h" #include "NamespaceImports.h" @@ -847,7 +849,7 @@ GetNextPc(jsbytecode* pc) /* * Disassemblers, for debugging only. */ -bool +extern MOZ_MUST_USE bool Disassemble(JSContext* cx, JS::Handle script, bool lines, Sprinter* sp); unsigned @@ -856,16 +858,9 @@ Disassemble1(JSContext* cx, JS::Handle script, jsbytecode* pc, unsign #endif -void -DumpPCCounts(JSContext* cx, JS::Handle script, Sprinter* sp); - -namespace jit { struct IonScriptCounts; } -void -DumpIonScriptCounts(js::Sprinter* sp, HandleScript script, - jit::IonScriptCounts* ionCounts); - -void +extern MOZ_MUST_USE bool DumpCompartmentPCCounts(JSContext* cx); + } // namespace js #endif /* jsopcode_h */ diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 6e4c9a387a78..24390b137ee8 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -8,11 +8,13 @@ #include "mozilla/ArrayUtils.h" #include "mozilla/Atomics.h" +#include "mozilla/Attributes.h" #include "mozilla/DebugOnly.h" #include "mozilla/GuardObjects.h" #include "mozilla/IntegerPrintfMacros.h" #include "mozilla/mozalloc.h" #include "mozilla/PodOperations.h" +#include "mozilla/ScopeExit.h" #include "mozilla/SizePrintfMacros.h" #include "mozilla/Sprintf.h" #include "mozilla/TimeStamp.h" @@ -108,6 +110,7 @@ using namespace js::shell; using mozilla::ArrayLength; using mozilla::Atomic; +using mozilla::MakeScopeExit; using mozilla::Maybe; using mozilla::Nothing; using mozilla::NumberEqualsInt32; @@ -2332,13 +2335,17 @@ UpdateSwitchTableBounds(JSContext* cx, HandleScript script, unsigned offset, *end = *start + (unsigned)(n * jmplen); } -static void +static MOZ_MUST_USE bool SrcNotes(JSContext* cx, HandleScript script, Sprinter* sp) { - Sprint(sp, "\nSource notes:\n"); - Sprint(sp, "%4s %4s %5s %6s %-8s %s\n", - "ofs", "line", "pc", "delta", "desc", "args"); - Sprint(sp, "---- ---- ----- ------ -------- ------\n"); + if (sp->put("\nSource notes:\n") < 0 || + !sp->jsprintf("%4s %4s %5s %6s %-8s %s\n", + "ofs", "line", "pc", "delta", "desc", "args") || + sp->put("---- ---- ----- ------ -------- ------\n") < 0) + { + return false; + } + unsigned offset = 0; unsigned colspan = 0; unsigned lineno = script->lineno(); @@ -2349,7 +2356,12 @@ SrcNotes(JSContext* cx, HandleScript script, Sprinter* sp) offset += delta; SrcNoteType type = (SrcNoteType) SN_TYPE(sn); const char* name = js_SrcNoteSpec[type].name; - Sprint(sp, "%3u: %4u %5u [%4u] %-8s", unsigned(sn - notes), lineno, offset, delta, name); + if (!sp->jsprintf("%3u: %4u %5u [%4u] %-8s", + unsigned(sn - notes), lineno, offset, delta, name)) + { + return false; + } + switch (type) { case SRC_NULL: case SRC_IF: @@ -2363,12 +2375,14 @@ SrcNotes(JSContext* cx, HandleScript script, Sprinter* sp) case SRC_COLSPAN: colspan = SN_OFFSET_TO_COLSPAN(GetSrcNoteOffset(sn, 0)); - Sprint(sp, "%d", colspan); + if (!sp->jsprintf("%d", colspan)) + return false; break; case SRC_SETLINE: lineno = GetSrcNoteOffset(sn, 0); - Sprint(sp, " lineno %u", lineno); + if (!sp->jsprintf(" lineno %u", lineno)) + return false; break; case SRC_NEWLINE: @@ -2376,31 +2390,38 @@ SrcNotes(JSContext* cx, HandleScript script, Sprinter* sp) break; case SRC_FOR: - Sprint(sp, " cond %u update %u tail %u", - unsigned(GetSrcNoteOffset(sn, 0)), - unsigned(GetSrcNoteOffset(sn, 1)), - unsigned(GetSrcNoteOffset(sn, 2))); + if (!sp->jsprintf(" cond %u update %u tail %u", + unsigned(GetSrcNoteOffset(sn, 0)), + unsigned(GetSrcNoteOffset(sn, 1)), + unsigned(GetSrcNoteOffset(sn, 2)))) + { + return false; + } break; case SRC_IF_ELSE: - Sprint(sp, " else %u", unsigned(GetSrcNoteOffset(sn, 0))); + if (!sp->jsprintf(" else %u", unsigned(GetSrcNoteOffset(sn, 0)))) + return false; break; case SRC_FOR_IN: case SRC_FOR_OF: - Sprint(sp, " closingjump %u", unsigned(GetSrcNoteOffset(sn, 0))); + if (!sp->jsprintf(" closingjump %u", unsigned(GetSrcNoteOffset(sn, 0)))) + return false; break; case SRC_COND: case SRC_WHILE: case SRC_NEXTCASE: - Sprint(sp, " offset %u", unsigned(GetSrcNoteOffset(sn, 0))); + if (!sp->jsprintf(" offset %u", unsigned(GetSrcNoteOffset(sn, 0)))) + return false; break; case SRC_TABLESWITCH: { JSOp op = JSOp(script->code()[offset]); MOZ_ASSERT(op == JSOP_TABLESWITCH); - Sprint(sp, " length %u", unsigned(GetSrcNoteOffset(sn, 0))); + if (!sp->jsprintf(" length %u", unsigned(GetSrcNoteOffset(sn, 0)))) + return false; UpdateSwitchTableBounds(cx, script, offset, &switchTableStart, &switchTableEnd); break; @@ -2408,10 +2429,12 @@ SrcNotes(JSContext* cx, HandleScript script, Sprinter* sp) case SRC_CONDSWITCH: { JSOp op = JSOp(script->code()[offset]); MOZ_ASSERT(op == JSOP_CONDSWITCH); - Sprint(sp, " length %u", unsigned(GetSrcNoteOffset(sn, 0))); - unsigned caseOff = (unsigned) GetSrcNoteOffset(sn, 1); - if (caseOff) - Sprint(sp, " first case offset %u", caseOff); + if (!sp->jsprintf(" length %u", unsigned(GetSrcNoteOffset(sn, 0)))) + return false; + if (unsigned caseOff = (unsigned) GetSrcNoteOffset(sn, 1)) { + if (!sp->jsprintf(" first case offset %u", caseOff)) + return false; + } UpdateSwitchTableBounds(cx, script, offset, &switchTableStart, &switchTableEnd); break; @@ -2419,15 +2442,18 @@ SrcNotes(JSContext* cx, HandleScript script, Sprinter* sp) case SRC_TRY: MOZ_ASSERT(JSOp(script->code()[offset]) == JSOP_TRY); - Sprint(sp, " offset to jump %u", unsigned(GetSrcNoteOffset(sn, 0))); + if (!sp->jsprintf(" offset to jump %u", unsigned(GetSrcNoteOffset(sn, 0)))) + return false; break; default: - MOZ_ASSERT(0); - break; + MOZ_ASSERT_UNREACHABLE("unrecognized srcnote"); } - Sprint(sp, "\n"); + if (sp->put("\n") < 0) + return false; } + + return true; } static bool @@ -2443,7 +2469,8 @@ Notes(JSContext* cx, unsigned argc, Value* vp) if (!script) return false; - SrcNotes(cx, script, &sprinter); + if (!SrcNotes(cx, script, &sprinter)) + return false; } JSString* str = JS_NewStringCopyZ(cx, sprinter.string()); @@ -2459,87 +2486,124 @@ JS_STATIC_ASSERT(JSTRY_FOR_IN == 2); static const char* const TryNoteNames[] = { "catch", "finally", "for-in", "for-of", "loop" }; -static bool +static MOZ_MUST_USE bool TryNotes(JSContext* cx, HandleScript script, Sprinter* sp) { if (!script->hasTrynotes()) return true; + if (sp->put("\nException table:\nkind stack start end\n") < 0) + return false; + JSTryNote* tn = script->trynotes()->vector; JSTryNote* tnlimit = tn + script->trynotes()->length; - Sprint(sp, "\nException table:\nkind stack start end\n"); do { MOZ_ASSERT(tn->kind < ArrayLength(TryNoteNames)); uint8_t startOff = script->pcToOffset(script->main()) + tn->start; - Sprint(sp, " %-7s %6u %8u %8u\n", - TryNoteNames[tn->kind], tn->stackDepth, - startOff, startOff + tn->length); + if (!sp->jsprintf(" %-7s %6u %8u %8u\n", + TryNoteNames[tn->kind], tn->stackDepth, + startOff, startOff + tn->length)) + { + return false; + } } while (++tn != tnlimit); return true; } -static bool +static MOZ_MUST_USE bool ScopeNotes(JSContext* cx, HandleScript script, Sprinter* sp) { if (!script->hasScopeNotes()) return true; - Sprint(sp, "\nScope notes:\n index parent start end\n"); + if (sp->put("\nScope notes:\n index parent start end\n") < 0) + return false; ScopeNoteArray* notes = script->scopeNotes(); for (uint32_t i = 0; i < notes->length; i++) { const ScopeNote* note = ¬es->vector[i]; - if (note->index == ScopeNote::NoScopeIndex) - Sprint(sp, "%8s ", "(none)"); - else - Sprint(sp, "%8u ", note->index); - if (note->parent == ScopeNote::NoScopeIndex) - Sprint(sp, "%8s ", "(none)"); - else - Sprint(sp, "%8u ", note->parent); - Sprint(sp, "%8u %8u\n", note->start, note->start + note->length); + if (note->index == ScopeNote::NoScopeIndex) { + if (!sp->jsprintf("%8s ", "(none)")) + return false; + } else { + if (!sp->jsprintf("%8u ", note->index)) + return false; + } + if (note->parent == ScopeNote::NoScopeIndex) { + if (!sp->jsprintf("%8s ", "(none)")) + return false; + } else { + if (!sp->jsprintf("%8u ", note->parent)) + return false; + } + if (!sp->jsprintf("%8u %8u\n", note->start, note->start + note->length)) + return false; } return true; } -static bool +static MOZ_MUST_USE bool DisassembleScript(JSContext* cx, HandleScript script, HandleFunction fun, bool lines, bool recursive, bool sourceNotes, Sprinter* sp) { if (fun) { - Sprint(sp, "flags:"); - if (fun->isLambda()) - Sprint(sp, " LAMBDA"); - if (fun->needsCallObject()) - Sprint(sp, " NEEDS_CALLOBJECT"); - if (fun->needsExtraBodyVarEnvironment()) - Sprint(sp, " NEEDS_EXTRABODYVARENV"); - if (fun->needsNamedLambdaEnvironment()) - Sprint(sp, " NEEDS_NAMEDLAMBDAENV"); - if (fun->isConstructor()) - Sprint(sp, " CONSTRUCTOR"); - if (fun->isExprBody()) - Sprint(sp, " EXPRESSION_CLOSURE"); - if (fun->isSelfHostedBuiltin()) - Sprint(sp, " SELF_HOSTED"); - if (fun->isArrow()) - Sprint(sp, " ARROW"); - Sprint(sp, "\n"); + if (sp->put("flags:") < 0) + return false; + if (fun->isLambda()) { + if (sp->put(" LAMBDA") < 0) + return false; + } + if (fun->needsCallObject()) { + if (sp->put(" NEEDS_CALLOBJECT") < 0) + return false; + } + if (fun->needsExtraBodyVarEnvironment()) { + if (sp->put(" NEEDS_EXTRABODYVARENV") < 0) + return false; + } + if (fun->needsNamedLambdaEnvironment()) { + if (sp->put(" NEEDS_NAMEDLAMBDAENV") < 0) + return false; + } + if (fun->isConstructor()) { + if (sp->put(" CONSTRUCTOR") < 0) + return false; + } + if (fun->isExprBody()) { + if (sp->put(" EXPRESSION_CLOSURE") < 0) + return false; + } + if (fun->isSelfHostedBuiltin()) { + if (sp->put(" SELF_HOSTED") < 0) + return false; + } + if (fun->isArrow()) { + if (sp->put(" ARROW") < 0) + return false; + } + if (sp->put("\n") < 0) + return false; } if (!Disassemble(cx, script, lines, sp)) return false; - if (sourceNotes) - SrcNotes(cx, script, sp); - TryNotes(cx, script, sp); - ScopeNotes(cx, script, sp); + if (sourceNotes) { + if (!SrcNotes(cx, script, sp)) + return false; + } + if (!TryNotes(cx, script, sp)) + return false; + if (!ScopeNotes(cx, script, sp)) + return false; if (recursive && script->hasObjects()) { ObjectArray* objects = script->objects(); for (unsigned i = 0; i != objects->length; ++i) { JSObject* obj = objects->vector[i]; if (obj->is()) { - Sprint(sp, "\n"); + if (sp->put("\n") < 0) + return false; + RootedFunction fun(cx, &obj->as()); if (fun->isInterpreted()) { RootedScript script(cx, fun->getOrCreateScript(cx)); @@ -2548,11 +2612,13 @@ DisassembleScript(JSContext* cx, HandleScript script, HandleFunction fun, return false; } } else { - Sprint(sp, "[native code]\n"); + if (sp->put("[native code]\n") < 0) + return false; } } } } + return true; } @@ -2606,9 +2672,12 @@ DisassembleToSprinter(JSContext* cx, unsigned argc, Value* vp, Sprinter* sprinte JSAutoCompartment ac(cx, script); if (!Disassemble(cx, script, p.lines, sprinter)) return false; - SrcNotes(cx, script, sprinter); - TryNotes(cx, script, sprinter); - ScopeNotes(cx, script, sprinter); + if (!SrcNotes(cx, script, sprinter)) + return false; + if (!TryNotes(cx, script, sprinter)) + return false; + if (!ScopeNotes(cx, script, sprinter)) + return false; } } else { for (unsigned i = 0; i < p.argc; i++) { @@ -2733,13 +2802,11 @@ DisassWithSrc(JSContext* cx, unsigned argc, Value* vp) const size_t lineBufLen = 512; unsigned len, line1, line2, bupline; - FILE* file; char linebuf[lineBufLen]; static const char sep[] = ";-------------------------"; - bool ok = true; RootedScript script(cx); - for (unsigned i = 0; ok && i < args.length(); i++) { + for (unsigned i = 0; i < args.length(); i++) { script = ValueToScript(cx, args[i]); if (!script) return false; @@ -2750,22 +2817,21 @@ DisassWithSrc(JSContext* cx, unsigned argc, Value* vp) return false; } - file = fopen(script->filename(), "r"); + FILE* file = fopen(script->filename(), "r"); if (!file) { JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr, JSSMSG_CANT_OPEN, script->filename(), strerror(errno)); return false; } + auto closeFile = MakeScopeExit([file]() { fclose(file); }); jsbytecode* pc = script->code(); jsbytecode* end = script->codeEnd(); Sprinter sprinter(cx); - if (!sprinter.init()) { - ok = false; - goto bail; - } + if (!sprinter.init()) + return false; /* burn the leading lines */ line2 = PCToLineNumber(script, pc); @@ -2773,8 +2839,7 @@ DisassWithSrc(JSContext* cx, unsigned argc, Value* vp) char* tmp = fgets(linebuf, lineBufLen, file); if (!tmp) { JS_ReportError(cx, "failed to read %s fully", script->filename()); - ok = false; - goto bail; + return false; } } @@ -2785,49 +2850,40 @@ DisassWithSrc(JSContext* cx, unsigned argc, Value* vp) if (line2 < line1) { if (bupline != line2) { bupline = line2; - if (Sprint(&sprinter, "%s %3u: BACKUP\n", sep, line2) == -1) { - ok = false; - goto bail; - } + if (!sprinter.jsprintf("%s %3u: BACKUP\n", sep, line2)) + return false; } } else { - if (bupline && line1 == line2) - if (Sprint(&sprinter, "%s %3u: RESTORE\n", sep, line2) == -1) { - ok = false; - goto bail; - } + if (bupline && line1 == line2) { + if (!sprinter.jsprintf("%s %3u: RESTORE\n", sep, line2)) + return false; + } bupline = 0; while (line1 < line2) { if (!fgets(linebuf, lineBufLen, file)) { JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr, JSSMSG_UNEXPECTED_EOF, script->filename()); - ok = false; - goto bail; + return false; } line1++; - if (Sprint(&sprinter, "%s %3u: %s", sep, line1, linebuf) == -1) { - ok = false; - goto bail; - } + if (!sprinter.jsprintf("%s %3u: %s", sep, line1, linebuf)) + return false; } } len = Disassemble1(cx, script, pc, script->pcToOffset(pc), true, &sprinter); - if (!len) { - ok = false; - goto bail; - } + if (!len) + return false; + pc += len; } fprintf(gOutFile->fp, "%s\n", sprinter.string()); - - bail: - fclose(file); } + args.rval().setUndefined(); - return ok; + return true; } #endif /* DEBUG */ @@ -4910,61 +4966,110 @@ class SprintOptimizationTypeInfoOp : public JS::ForEachTrackedOptimizationTypeIn { Sprinter* sp; bool startedTypes_; + bool hadError_; public: explicit SprintOptimizationTypeInfoOp(Sprinter* sp) : sp(sp), - startedTypes_(false) + startedTypes_(false), + hadError_(false) { } void readType(const char* keyedBy, const char* name, const char* location, Maybe lineno) override { - if (!startedTypes_) { - startedTypes_ = true; - Sprint(sp, "{\"typeset\": ["); - } - Sprint(sp, "{\"keyedBy\":\"%s\"", keyedBy); - if (name) - Sprint(sp, ",\"name\":\"%s\"", name); - if (location) { - char buf[512]; - PutEscapedString(buf, mozilla::ArrayLength(buf), location, strlen(location), '"'); - Sprint(sp, ",\"location\":%s", buf); - } - if (lineno.isSome()) - Sprint(sp, ",\"line\":%u", *lineno); - Sprint(sp, "},"); + if (hadError_) + return; + + do { + if (!startedTypes_) { + startedTypes_ = true; + if (sp->put("{\"typeset\": [") < 0) + break; + } + + if (!sp->jsprintf("{\"keyedBy\":\"%s\"", keyedBy)) + break; + + if (name) { + if (!sp->jsprintf(",\"name\":\"%s\"", name)) + break; + } + + if (location) { + char buf[512]; + PutEscapedString(buf, mozilla::ArrayLength(buf), location, strlen(location), '"'); + if (!sp->jsprintf(",\"location\":%s", buf)) + break; + } + if (lineno.isSome()) { + if (!sp->jsprintf(",\"line\":%u", *lineno)) + break; + } + if (sp->put("},") < 0) + break; + + return; + } while (false); + + hadError_ = true; } void operator()(JS::TrackedTypeSite site, const char* mirType) override { - if (startedTypes_) { - // Clear trailing , - if ((*sp)[sp->getOffset() - 1] == ',') - (*sp)[sp->getOffset() - 1] = ' '; - Sprint(sp, "],"); - startedTypes_ = false; - } else { - Sprint(sp, "{"); - } + if (hadError_) + return; - Sprint(sp, "\"site\":\"%s\",\"mirType\":\"%s\"},", - TrackedTypeSiteString(site), mirType); + do { + if (startedTypes_) { + // Clear trailing , + if ((*sp)[sp->getOffset() - 1] == ',') + (*sp)[sp->getOffset() - 1] = ' '; + if (sp->put("],") < 0) + break; + + startedTypes_ = false; + } else { + if (sp->put("{") < 0) + break; + } + + if (!sp->jsprintf("\"site\":\"%s\",\"mirType\":\"%s\"},", + TrackedTypeSiteString(site), mirType)) + { + break; + } + + return; + } while (false); + + hadError_ = true; + } + + bool hadError() const { + return hadError_; } }; class SprintOptimizationAttemptsOp : public JS::ForEachTrackedOptimizationAttemptOp { Sprinter* sp; + bool hadError_; public: explicit SprintOptimizationAttemptsOp(Sprinter* sp) - : sp(sp) + : sp(sp), hadError_(false) { } void operator()(JS::TrackedStrategy strategy, JS::TrackedOutcome outcome) override { - Sprint(sp, "{\"strategy\":\"%s\",\"outcome\":\"%s\"},", - TrackedStrategyString(strategy), TrackedOutcomeString(outcome)); + if (hadError_) + return; + + hadError_ = !sp->jsprintf("{\"strategy\":\"%s\",\"outcome\":\"%s\"},", + TrackedStrategyString(strategy), TrackedOutcomeString(outcome)); + } + + bool hadError() const { + return hadError_; } }; @@ -5018,7 +5123,9 @@ ReflectTrackedOptimizations(JSContext* cx, unsigned argc, Value* vp) const jit::IonTrackedOptimizationsRegionTable* regions = entry.ionEntry().trackedOptimizationsRegionTable(); - Sprint(&sp, "{\"regions\": ["); + if (sp.put("{\"regions\": [") < 0) + return false; + for (uint32_t i = 0; i < regions->numEntries(); i++) { jit::IonTrackedOptimizationsRegion region = regions->entry(i); jit::IonTrackedOptimizationsRegion::RangeIterator iter = region.ranges(); @@ -5026,6 +5133,7 @@ ReflectTrackedOptimizations(JSContext* cx, unsigned argc, Value* vp) uint32_t startOffset, endOffset; uint8_t index; iter.readNext(&startOffset, &endOffset, &index); + JSScript* script; jsbytecode* pc; // Use endOffset, as startOffset may be associated with a @@ -5035,31 +5143,54 @@ ReflectTrackedOptimizations(JSContext* cx, unsigned argc, Value* vp) // the second region and not the first. uint8_t* addr = ion->method()->raw() + endOffset; entry.youngestFrameLocationAtAddr(rt, addr, &script, &pc); - Sprint(&sp, "{\"location\":\"%s:%u\",\"offset\":%u,\"index\":%u}%s", - script->filename(), script->lineno(), script->pcToOffset(pc), index, - iter.more() ? "," : ""); + + if (!sp.jsprintf("{\"location\":\"%s:%u\",\"offset\":%u,\"index\":%u}%s", + script->filename(), script->lineno(), script->pcToOffset(pc), index, + iter.more() ? "," : "")) + { + return false; + } } } - Sprint(&sp, "],"); - Sprint(&sp, "\"opts\": ["); + if (sp.put("],") < 0) + return false; + + if (sp.put("\"opts\": [") < 0) + return false; + for (uint8_t i = 0; i < entry.ionEntry().numOptimizationAttempts(); i++) { - Sprint(&sp, "%s{\"typeinfo\":[", i == 0 ? "" : ","); + if (!sp.jsprintf("%s{\"typeinfo\":[", i == 0 ? "" : ",")) + return false; + SprintOptimizationTypeInfoOp top(&sp); jit::IonTrackedOptimizationsTypeInfo::ForEachOpAdapter adapter(top); entry.trackedOptimizationTypeInfo(i).forEach(adapter, entry.allTrackedTypes()); + if (top.hadError()) + return false; + // Clear the trailing , if (sp[sp.getOffset() - 1] == ',') sp[sp.getOffset() - 1] = ' '; - Sprint(&sp, "],\"attempts\":["); + + if (sp.put("],\"attempts\":[") < 0) + return false; + SprintOptimizationAttemptsOp aop(&sp); entry.trackedOptimizationAttempts(i).forEach(aop); + if (aop.hadError()) + return false; + // Clear the trailing , if (sp[sp.getOffset() - 1] == ',') sp[sp.getOffset() - 1] = ' '; - Sprint(&sp, "]}"); + + if (sp.put("]}") < 0) + return false; } - Sprint(&sp, "]}"); + + if (sp.put("]}") < 0) + return false; if (sp.hadOutOfMemory()) return false; @@ -7292,8 +7423,11 @@ Shell(JSContext* cx, OptionParser* op, char** envp) if (sc->exitCode) result = sc->exitCode; - if (enableDisassemblyDumps) - js::DumpCompartmentPCCounts(cx); + if (enableDisassemblyDumps) { + AutoReportException are(cx); + if (!js::DumpCompartmentPCCounts(cx)) + result = EXITCODE_OUT_OF_MEMORY; + } if (!op->getBoolOption("no-js-cache-per-process")) { if (jsCacheAsmJSPath) { diff --git a/js/src/vm/Printer.cpp b/js/src/vm/Printer.cpp index 54cb939e689a..88350a4bd5a2 100644 --- a/js/src/vm/Printer.cpp +++ b/js/src/vm/Printer.cpp @@ -260,23 +260,20 @@ Sprinter::reportOutOfMemory() hadOOM_ = true; } -ptrdiff_t -Sprint(Sprinter* sp, const char* format, ...) +bool +Sprinter::jsprintf(const char* format, ...) { va_list ap; - char* bp; - ptrdiff_t offset; - va_start(ap, format); - bp = JS_vsmprintf(format, ap); /* XXX vsaprintf */ + + UniquePtr chars(JS_vsmprintf(format, ap)); /* XXX vsaprintf */ va_end(ap); - if (!bp) { - sp->reportOutOfMemory(); - return -1; + if (!chars) { + reportOutOfMemory(); + return false; } - offset = sp->put(bp); - js_free(bp); - return offset; + + return put(chars.get()) >= 0; } const char js_EscapeMap[] = { @@ -299,8 +296,10 @@ QuoteString(Sprinter* sp, const CharT* s, size_t length, char16_t quote) /* Sample off first for later return value pointer computation. */ ptrdiff_t offset = sp->getOffset(); - if (quote && Sprint(sp, "%c", char(quote)) < 0) - return nullptr; + if (quote) { + if (!sp->jsprintf("%c", char(quote))) + return nullptr; + } const CharT* end = s + length; @@ -331,7 +330,7 @@ QuoteString(Sprinter* sp, const CharT* s, size_t length, char16_t quote) /* Use js_EscapeMap, \u, or \x only if necessary. */ const char* escape; if (!(c >> 8) && c != 0 && (escape = strchr(js_EscapeMap, int(c))) != nullptr) { - if (Sprint(sp, "\\%c", escape[1]) < 0) + if (!sp->jsprintf("\\%c", escape[1])) return nullptr; } else { /* @@ -339,21 +338,25 @@ QuoteString(Sprinter* sp, const CharT* s, size_t length, char16_t quote) * because ECMA-262 allows only \u, not \x, in Unicode identifiers * (see bug 621814). */ - if (Sprint(sp, (quote && !(c >> 8)) ? "\\x%02X" : "\\u%04X", c) < 0) + if (!sp->jsprintf((quote && !(c >> 8)) ? "\\x%02X" : "\\u%04X", c)) return nullptr; } } /* Sprint the closing quote and return the quoted string. */ - if (quote && Sprint(sp, "%c", char(quote)) < 0) - return nullptr; + if (quote) { + if (!sp->jsprintf("%c", char(quote))) + return nullptr; + } /* * If we haven't Sprint'd anything yet, Sprint an empty string so that * the return below gives a valid result. */ - if (offset == sp->getOffset() && Sprint(sp, "") < 0) - return nullptr; + if (offset == sp->getOffset()) { + if (sp->put("") < 0) + return nullptr; + } return sp->stringAt(offset); } diff --git a/js/src/vm/Printer.h b/js/src/vm/Printer.h index b64a81aa5987..0cc19c342fcb 100644 --- a/js/src/vm/Printer.h +++ b/js/src/vm/Printer.h @@ -111,6 +111,11 @@ class Sprinter final : public GenericPrinter virtual int put(const char* s, size_t len) override; using GenericPrinter::put; // pick up |inline int put(const char* s);| + // Format the given format/arguments as if by JS_vsmprintf, then put it. + // Return true on success, else return false and report an error (typically + // OOM). + MOZ_MUST_USE bool jsprintf(const char* fmt, ...); + // Prints a formatted string into the buffer. virtual int vprintf(const char* fmt, va_list ap) override; @@ -209,9 +214,6 @@ class LSprinter final : public GenericPrinter virtual bool hadOutOfMemory() const override; }; -extern ptrdiff_t -Sprint(Sprinter* sp, const char* format, ...); - // Map escaped code to the letter/symbol escaped with a backslash. extern const char js_EscapeMap[]; From 96c052cf1f971d8c6abda0bf6b151d2f523cf9b4 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Thu, 22 Sep 2016 15:07:01 -0600 Subject: [PATCH 074/102] Bug 1304883: Modify mscom::MainThreadInvoker and Win32 widget to use atomic boolean to flag pending APCs; r=jimm MozReview-Commit-ID: 7fXoDkBEd2V --HG-- extra : rebase_source : 1960f9bf8294bfea15209554dd7fdc0ce1df5dcc --- ipc/mscom/MainThreadInvoker.cpp | 34 +++++++--------------------- widget/windows/WinUtils.cpp | 40 ++++++++++++++++++++++++++++++++- widget/windows/WinUtils.h | 4 ++++ 3 files changed, 51 insertions(+), 27 deletions(-) diff --git a/ipc/mscom/MainThreadInvoker.cpp b/ipc/mscom/MainThreadInvoker.cpp index 2c6406ae0fc4..9e57d9a29ebc 100644 --- a/ipc/mscom/MainThreadInvoker.cpp +++ b/ipc/mscom/MainThreadInvoker.cpp @@ -14,8 +14,7 @@ #include "mozilla/HangMonitor.h" #include "mozilla/RefPtr.h" #include "private/prpriv.h" // For PR_GetThreadID - -#include // For NTSTATUS and NTAPI +#include "WinUtils.h" namespace { @@ -42,15 +41,12 @@ private: nsCOMPtr mRunnable; }; -typedef NTSTATUS (NTAPI* NtTestAlertPtr)(VOID); - } // anonymous namespace namespace mozilla { namespace mscom { HANDLE MainThreadInvoker::sMainThread = nullptr; -StaticRefPtr MainThreadInvoker::sAlertRunnable; /* static */ bool MainThreadInvoker::InitStatics() @@ -67,25 +63,11 @@ MainThreadInvoker::InitStatics() } PRUint32 tid = ::PR_GetThreadID(mainPrThread); sMainThread = ::OpenThread(SYNCHRONIZE | THREAD_SET_CONTEXT, FALSE, tid); - if (!sMainThread) { - return false; - } - NtTestAlertPtr NtTestAlert = - reinterpret_cast( - ::GetProcAddress(::GetModuleHandleW(L"ntdll.dll"), "NtTestAlert")); - sAlertRunnable = ::NS_NewRunnableFunction([NtTestAlert]() -> void { - // We're using NtTestAlert() instead of SleepEx() so that the main thread - // never gives up its quantum if there are no APCs pending. - NtTestAlert(); - }).take(); - if (sAlertRunnable) { - ClearOnShutdown(&sAlertRunnable); - } - return !!sAlertRunnable; + return !!sMainThread; } MainThreadInvoker::MainThreadInvoker() - : mDoneEvent(::CreateEvent(nullptr, FALSE, FALSE, nullptr)) + : mDoneEvent(::CreateEventW(nullptr, FALSE, FALSE, nullptr)) { static const bool gotStatics = InitStatics(); MOZ_ASSERT(gotStatics); @@ -129,11 +111,11 @@ MainThreadInvoker::Invoke(already_AddRefed&& aRunnable, wrappedRunnable->Release(); return false; } - // We should enqueue a call to NtTestAlert() so that the main thread will - // check for APCs during event processing. If we omit this then the main - // thread will not check its APC queue until it is idle. Note that failing to - // dispatch this event is non-fatal, but it will delay execution of the APC. - Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(sAlertRunnable))); + // We should ensure a call to NtTestAlert() is made on the main thread so + // that the main thread will check for APCs during event processing. If we + // omit this then the main thread will not check its APC queue until it is + // idle. + widget::WinUtils::SetAPCPending(); return WaitForCompletion(aTimeout); } diff --git a/widget/windows/WinUtils.cpp b/widget/windows/WinUtils.cpp index e44bf79b93d3..66ee0cc412d0 100644 --- a/widget/windows/WinUtils.cpp +++ b/widget/windows/WinUtils.cpp @@ -452,6 +452,11 @@ struct CoTaskMemFreePolicy SetThreadDpiAwarenessContextProc WinUtils::sSetThreadDpiAwarenessContext = NULL; EnableNonClientDpiScalingProc WinUtils::sEnableNonClientDpiScaling = NULL; +#ifdef ACCESSIBILITY +typedef NTSTATUS (NTAPI* NtTestAlertPtr)(VOID); +static NtTestAlertPtr sNtTestAlert = nullptr; +#endif + /* static */ void @@ -486,6 +491,12 @@ WinUtils::Initialize() ::GetProcAddress(user32Dll, "SetThreadDpiAwarenessContext"); } } + +#ifdef ACCESSIBILITY + sNtTestAlert = reinterpret_cast( + ::GetProcAddress(::GetModuleHandleW(L"ntdll.dll"), "NtTestAlert")); + MOZ_ASSERT(sNtTestAlert); +#endif } // static @@ -691,11 +702,31 @@ WinUtils::MonitorFromRect(const gfx::Rect& rect) return ::MonitorFromRect(&globalWindowBounds, MONITOR_DEFAULTTONEAREST); } +#ifdef ACCESSIBILITY +#ifndef STATUS_SUCCESS +#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) +#endif + +static Atomic sAPCPending; + +/* static */ +void +WinUtils::SetAPCPending() +{ + sAPCPending = true; +} +#endif // ACCESSIBILITY + /* static */ bool WinUtils::PeekMessage(LPMSG aMsg, HWND aWnd, UINT aFirstMessage, UINT aLastMessage, UINT aOption) { +#ifdef ACCESSIBILITY + if (NS_IsMainThread() && sAPCPending.exchange(false)) { + while (sNtTestAlert() != STATUS_SUCCESS) ; + } +#endif #ifdef NS_ENABLE_TSF ITfMessagePump* msgPump = TSFTextStore::GetMessagePump(); if (msgPump) { @@ -764,14 +795,21 @@ WinUtils::WaitForMessage(DWORD aTimeoutMs) if (result == WAIT_TIMEOUT) { break; } +#if defined(ACCESSIBILITY) if (result == WAIT_IO_COMPLETION) { if (NS_IsMainThread()) { + if (sAPCPending.exchange(false)) { + // Clear out any pending APCs + while (sNtTestAlert() != STATUS_SUCCESS) ; + } // We executed an APC that would have woken up the hang monitor. Since - // we're now going to sleep again, we should notify the hang monitor. + // there are no more APCs pending and we are now going to sleep again, + // we should notify the hang monitor. mozilla::HangMonitor::Suspend(); } continue; } +#endif // defined(ACCESSIBILITY) // Sent messages (via SendMessage and friends) are processed differently // than queued messages (via PostMessage); the destination window procedure diff --git a/widget/windows/WinUtils.h b/widget/windows/WinUtils.h index 299f9bad1e40..69d73528cb7f 100644 --- a/widget/windows/WinUtils.h +++ b/widget/windows/WinUtils.h @@ -519,6 +519,10 @@ public: */ static bool GetAppInitDLLs(nsAString& aOutput); +#ifdef ACCESSIBILITY + static void SetAPCPending(); +#endif + private: typedef HRESULT (WINAPI * SHCreateItemFromParsingNamePtr)(PCWSTR pszPath, IBindCtx *pbc, From a47ce92ac2266eb80591193fa3009a9de04e8bbb Mon Sep 17 00:00:00 2001 From: James Andreou Date: Tue, 30 Aug 2016 17:54:58 -0400 Subject: [PATCH 075/102] Bug 1282124 - Remove nsILoadInfo.usePrivateBrowsing and the SEC_FORCE_PRIVATE_BROWSING flag; r=smaug,jryans --- devtools/shared/DevToolsUtils.js | 70 ++++++++++------------ docshell/base/nsDocShell.cpp | 4 -- dom/html/HTMLMediaElement.cpp | 10 ---- image/imgLoader.cpp | 20 +++++-- image/imgLoader.h | 3 - image/test/unit/test_private_channel.js | 15 +++-- netwerk/base/LoadInfo.cpp | 43 +++++-------- netwerk/base/nsILoadInfo.idl | 18 +----- netwerk/base/nsNetUtil.cpp | 17 +----- netwerk/protocol/http/HttpChannelChild.cpp | 3 - netwerk/test/unit/test_cacheflags.js | 25 ++++---- 11 files changed, 91 insertions(+), 137 deletions(-) diff --git a/devtools/shared/DevToolsUtils.js b/devtools/shared/DevToolsUtils.js index 1cecf6159e77..d44184fd6b8e 100644 --- a/devtools/shared/DevToolsUtils.js +++ b/devtools/shared/DevToolsUtils.js @@ -380,7 +380,8 @@ exports.defineLazyGetter(this, "NetworkHelper", () => { * - window: the window to get the loadGroup from * - charset: the charset to use if the channel doesn't provide one * - principal: the principal to use, if omitted, the request is loaded - * with the system principal + * with a codebase principal corresponding to the url being + * loaded, using the origin attributes of the window, if any. * - cacheKey: when loading from cache, use this key to retrieve a cache * specific to a given SHEntry. (Allows loading POST * requests from cache) @@ -526,51 +527,44 @@ function mainThreadFetch(aURL, aOptions = { loadFromCache: true, */ function newChannelForURL(url, { policy, window, principal }) { var securityFlags = Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL; - if (window) { - // Respect private browsing. - var req = window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocumentLoader) - .loadGroup; - if (req) { - var nc = req.notificationCallbacks; - if (nc) { - try { - var lc = nc.getInterface(Ci.nsILoadContext); - if (lc) { - if (lc.usePrivateBrowsing) { - securityFlags |= Ci.nsILoadInfo.SEC_FORCE_PRIVATE_BROWSING; - } - } - } catch (ex) {} - } - } - } - - let channelOptions = { - contentPolicyType: policy, - securityFlags: securityFlags, - uri: url - }; - if (principal) { - // contentPolicyType is required when loading with a custom principal - if (!channelOptions.contentPolicyType) { - channelOptions.contentPolicyType = Ci.nsIContentPolicy.TYPE_OTHER; - } - channelOptions.loadingPrincipal = principal; - } else { - channelOptions.loadUsingSystemPrincipal = true; - } + let uri; try { - return NetUtil.newChannel(channelOptions); + uri = Services.io.newURI(url, null, null); } catch (e) { // In the xpcshell tests, the script url is the absolute path of the test // file, which will make a malformed URI error be thrown. Add the file // scheme to see if it helps. - channelOptions.uri = "file://" + url; + uri = Services.io.newURI("file://" + url, null, null); + } + let channelOptions = { + contentPolicyType: policy, + securityFlags: securityFlags, + uri: uri + }; + let prin = principal; + if (!prin) { + let oa = {}; + if (window) { + oa = window.document.nodePrincipal.originAttributes; + } + prin = Services.scriptSecurityManager + .createCodebasePrincipal(uri, oa); + } + // contentPolicyType is required when specifying a principal + if (!channelOptions.contentPolicyType) { + channelOptions.contentPolicyType = Ci.nsIContentPolicy.TYPE_OTHER; + } + channelOptions.loadingPrincipal = prin; + try { return NetUtil.newChannel(channelOptions); + } catch (e) { + // In xpcshell tests on Windows, nsExternalProtocolHandler::NewChannel() + // can throw NS_ERROR_UNKNOWN_PROTOCOL if the external protocol isn't + // supported by Windows, so we also need to handle the exception here if + // parsing the URL above doesn't throw. + return newChannelForURL("file://" + url, { policy, window, principal }); } } diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index dde9ad47da8e..7288de9bb256 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -10857,10 +10857,6 @@ nsDocShell::DoURILoad(nsIURI* aURI, securityFlags |= nsILoadInfo::SEC_SANDBOXED; } - if (UsePrivateBrowsing()) { - securityFlags |= nsILoadInfo::SEC_FORCE_PRIVATE_BROWSING; - } - nsCOMPtr loadInfo = (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT) ? new LoadInfo(loadingWindow, triggeringPrincipal, diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index c96a5fb12fb3..3bccb6e0f800 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -565,16 +565,6 @@ public: ? nsIContentPolicy::TYPE_INTERNAL_AUDIO : nsIContentPolicy::TYPE_INTERNAL_VIDEO; - nsCOMPtr docShell = aElement->OwnerDoc()->GetDocShell(); - if (docShell) { - nsDocShell* docShellPtr = nsDocShell::Cast(docShell); - bool privateBrowsing; - docShellPtr->GetUsePrivateBrowsing(&privateBrowsing); - if (privateBrowsing) { - securityFlags |= nsILoadInfo::SEC_FORCE_PRIVATE_BROWSING; - } - } - nsCOMPtr loadGroup = aElement->GetDocumentLoadGroup(); nsCOMPtr channel; nsresult rv = NS_NewChannel(getter_AddRefs(channel), diff --git a/image/imgLoader.cpp b/image/imgLoader.cpp index 1e9ebf9a4f47..71515a1e8480 100644 --- a/image/imgLoader.cpp +++ b/image/imgLoader.cpp @@ -729,10 +729,6 @@ NewImageChannel(nsIChannel** aResult, } securityFlags |= nsILoadInfo::SEC_ALLOW_CHROME; - if (aRespectPrivacy) { - securityFlags |= nsILoadInfo::SEC_FORCE_PRIVATE_BROWSING; - } - // Note we are calling NS_NewChannelWithTriggeringPrincipal() here with a // node and a principal. This is for things like background images that are // specified by user stylesheets, where the document is being styled, but @@ -763,6 +759,22 @@ NewImageChannel(nsIChannel** aResult, nullptr, // loadGroup callbacks, aLoadFlags); + + if (NS_FAILED(rv)) { + return rv; + } + + // Use the OriginAttributes from the loading principal, if one is available, + // and adjust the private browsing ID based on what kind of load the caller + // has asked us to perform. + NeckoOriginAttributes neckoAttrs; + if (aLoadingPrincipal) { + neckoAttrs.InheritFromDocToNecko(BasePrincipal::Cast(aLoadingPrincipal)->OriginAttributesRef()); + } + neckoAttrs.mPrivateBrowsingId = aRespectPrivacy ? 1 : 0; + + nsCOMPtr loadInfo = (*aResult)->GetLoadInfo(); + rv = loadInfo->SetOriginAttributes(neckoAttrs); } if (NS_FAILED(rv)) { diff --git a/image/imgLoader.h b/image/imgLoader.h index 9bff3a82ec0b..20022cd0c2fd 100644 --- a/image/imgLoader.h +++ b/image/imgLoader.h @@ -255,9 +255,6 @@ public: /** * Get the Private Browsing image loader instance that is used by gecko code, * creating it if necessary. - * - * The nsIChannel objects that this instance creates are created with the - * nsILoadInfo::SEC_FORCE_PRIVATE_BROWSING flag. */ static imgLoader* PrivateBrowsingLoader(); diff --git a/image/test/unit/test_private_channel.js b/image/test/unit/test_private_channel.js index bf20af59526f..960d6d69bd21 100644 --- a/image/test/unit/test_private_channel.js +++ b/image/test/unit/test_private_channel.js @@ -33,6 +33,7 @@ var requests = []; var listeners = []; function NotificationCallbacks(isPrivate) { + this.originAttributes.privateBrowsingId = isPrivate ? 1 : 0; this.usePrivateBrowsing = isPrivate; } @@ -48,7 +49,9 @@ NotificationCallbacks.prototype = { return this; throw Cr.NS_ERROR_NO_INTERFACE; }, - originAttributes: {} + originAttributes: { + privateBrowsingId: 0 + } }; var gImgPath = 'http://localhost:' + server.identity.primaryPort + '/image.png'; @@ -56,11 +59,11 @@ var gImgPath = 'http://localhost:' + server.identity.primaryPort + '/image.png'; function setup_chan(path, isPrivate, callback) { var uri = NetUtil.newURI(gImgPath); var securityFlags = Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL; - if (isPrivate) { - securityFlags |= Ci.nsILoadInfo.SEC_FORCE_PRIVATE_BROWSING; - } - var chan = NetUtil.newChannel({uri: uri, loadUsingSystemPrincipal: true, - securityFlags: securityFlags}); + var principal = Services.scriptSecurityManager + .createCodebasePrincipal(uri, {privateBrowsingId: isPrivate ? 1 : 0}); + var chan = NetUtil.newChannel({uri: uri, loadingPrincipal: principal, + securityFlags: securityFlags, + contentPolicyType: Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE}); chan.notificationCallbacks = new NotificationCallbacks(isPrivate); var channelListener = new ChannelListener(); chan.asyncOpen2(channelListener); diff --git a/netwerk/base/LoadInfo.cpp b/netwerk/base/LoadInfo.cpp index 4453faaddc08..1617fd84c10b 100644 --- a/netwerk/base/LoadInfo.cpp +++ b/netwerk/base/LoadInfo.cpp @@ -177,31 +177,31 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal, } } - if (!(mSecurityFlags & nsILoadInfo::SEC_FORCE_PRIVATE_BROWSING)) { - if (aLoadingContext) { - nsCOMPtr loadContext = - aLoadingContext->OwnerDoc()->GetLoadContext(); - if (loadContext) { - bool usePrivateBrowsing; - nsresult rv = loadContext->GetUsePrivateBrowsing(&usePrivateBrowsing); - if (NS_SUCCEEDED(rv) && usePrivateBrowsing) { - mSecurityFlags |= nsILoadInfo::SEC_FORCE_PRIVATE_BROWSING; - } + InheritOriginAttributes(mLoadingPrincipal, mOriginAttributes); + + // We need to do this after inheriting the document's origin attributes + // above, in case the loading principal ends up being the system principal. + if (aLoadingContext) { + nsCOMPtr loadContext = + aLoadingContext->OwnerDoc()->GetLoadContext(); + nsCOMPtr docShell = aLoadingContext->OwnerDoc()->GetDocShell(); + if (loadContext && docShell && + docShell->ItemType() == nsIDocShellTreeItem::typeContent) { + bool usePrivateBrowsing; + nsresult rv = loadContext->GetUsePrivateBrowsing(&usePrivateBrowsing); + if (NS_SUCCEEDED(rv)) { + mOriginAttributes.SyncAttributesWithPrivateBrowsing(usePrivateBrowsing); } } } - InheritOriginAttributes(mLoadingPrincipal, mOriginAttributes); - // For chrome docshell, the mPrivateBrowsingId remains 0 even its // UsePrivateBrowsing() is true, so we only update the mPrivateBrowsingId in // origin attributes if the type of the docshell is content. if (aLoadingContext) { nsCOMPtr docShell = aLoadingContext->OwnerDoc()->GetDocShell(); if (docShell) { - if (docShell->ItemType() == nsIDocShellTreeItem::typeContent) { - mOriginAttributes.SyncAttributesWithPrivateBrowsing(GetUsePrivateBrowsing()); - } else if (docShell->ItemType() == nsIDocShellTreeItem::typeChrome) { + if (docShell->ItemType() == nsIDocShellTreeItem::typeChrome) { MOZ_ASSERT(mOriginAttributes.mPrivateBrowsingId == 0, "chrome docshell shouldn't have mPrivateBrowsingId set."); } @@ -264,10 +264,7 @@ LoadInfo::LoadInfo(nsPIDOMWindowOuter* aOuterWindow, const DocShellOriginAttributes attrs = nsDocShell::Cast(docShell)->GetOriginAttributes(); - if (docShell->ItemType() == nsIDocShellTreeItem::typeContent) { - MOZ_ASSERT(GetUsePrivateBrowsing() == (attrs.mPrivateBrowsingId != 0), - "docshell and mSecurityFlags have different value for PrivateBrowsing()."); - } else if (docShell->ItemType() == nsIDocShellTreeItem::typeChrome) { + if (docShell->ItemType() == nsIDocShellTreeItem::typeChrome) { MOZ_ASSERT(attrs.mPrivateBrowsingId == 0, "chrome docshell shouldn't have mPrivateBrowsingId set."); } @@ -586,14 +583,6 @@ LoadInfo::GetDontFollowRedirects(bool* aResult) return NS_OK; } -NS_IMETHODIMP -LoadInfo::GetUsePrivateBrowsing(bool* aUsePrivateBrowsing) -{ - *aUsePrivateBrowsing = (mSecurityFlags & - nsILoadInfo::SEC_FORCE_PRIVATE_BROWSING); - return NS_OK; -} - NS_IMETHODIMP LoadInfo::GetLoadErrorPage(bool* aResult) { diff --git a/netwerk/base/nsILoadInfo.idl b/netwerk/base/nsILoadInfo.idl index 9770490b6444..fa66bf3792a2 100644 --- a/netwerk/base/nsILoadInfo.idl +++ b/netwerk/base/nsILoadInfo.idl @@ -174,20 +174,11 @@ interface nsILoadInfo : nsISupports */ const unsigned long SEC_DONT_FOLLOW_REDIRECTS = (1<<12); - /** - * Force private browsing. Setting this flag the private browsing can be - * enforce even when a loading is not happening in the context of a document. - * - * If the flag is true, even if a document context is present, - * GetUsePrivateBrowsing will always return true. - */ - const unsigned long SEC_FORCE_PRIVATE_BROWSING = (1<<13); - /** * Load an error page, it should be one of following : about:neterror, * about:certerror, about:blocked, or about:tabcrashed. */ - const unsigned long SEC_LOAD_ERROR_PAGE = (1<<14); + const unsigned long SEC_LOAD_ERROR_PAGE = (1<<13); /** * This is the principal of the network request's caller/requester where @@ -350,13 +341,6 @@ interface nsILoadInfo : nsISupports */ [infallible] readonly attribute boolean aboutBlankInherits; - /** - * If usePrivateBrowsing is true, private browsing will be used. - * This value equals to originAttributes.privateBrowsingId in *content* - * side. - */ - [infallible] readonly attribute boolean usePrivateBrowsing; - /** * If allowChrome is true, then use nsIScriptSecurityManager::ALLOW_CHROME * when calling CheckLoadURIWithPrincipal(). diff --git a/netwerk/base/nsNetUtil.cpp b/netwerk/base/nsNetUtil.cpp index 39fa8a2ccab7..ca777cde8e37 100644 --- a/netwerk/base/nsNetUtil.cpp +++ b/netwerk/base/nsNetUtil.cpp @@ -2424,21 +2424,12 @@ NS_CompareLoadInfoAndLoadContext(nsIChannel *aChannel) DocShellOriginAttributes originAttrsLoadContext; loadContext->GetOriginAttributes(originAttrsLoadContext); - bool loadInfoUsePB = loadInfo->GetUsePrivateBrowsing(); - bool loadContextUsePB = false; - rv = loadContext->GetUsePrivateBrowsing(&loadContextUsePB); - if (NS_FAILED(rv)) { - return NS_ERROR_UNEXPECTED; - } - - LOG(("NS_CompareLoadInfoAndLoadContext - loadInfo: %d, %d, %d, %d, %d; " - "loadContext: %d %d, %d, %d, %d. [channel=%p]", + LOG(("NS_CompareLoadInfoAndLoadContext - loadInfo: %d, %d, %d, %d; " + "loadContext: %d %d, %d, %d. [channel=%p]", originAttrsLoadInfo.mAppId, originAttrsLoadInfo.mInIsolatedMozBrowser, originAttrsLoadInfo.mUserContextId, originAttrsLoadInfo.mPrivateBrowsingId, - loadInfoUsePB, loadContextAppId, loadContextIsInBE, originAttrsLoadContext.mUserContextId, originAttrsLoadContext.mPrivateBrowsingId, - loadContextUsePB, aChannel)); MOZ_ASSERT(originAttrsLoadInfo.mAppId == loadContextAppId, @@ -2460,10 +2451,6 @@ NS_CompareLoadInfoAndLoadContext(nsIChannel *aChannel) "The value of mPrivateBrowsingId in the loadContext and in the " "loadInfo are not the same!"); - MOZ_ASSERT(loadInfoUsePB == loadContextUsePB, - "The value of usePrivateBrowsing in the loadContext and in the loadInfo " - "are not the same!"); - return NS_OK; } diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp index 1272010194ed..1ea1fac720a1 100644 --- a/netwerk/protocol/http/HttpChannelChild.cpp +++ b/netwerk/protocol/http/HttpChannelChild.cpp @@ -1795,9 +1795,6 @@ HttpChannelChild::AsyncOpen(nsIStreamListener *listener, nsISupports *aContext) LOG(("HttpChannelChild::AsyncOpen [this=%p uri=%s]\n", this, mSpec.get())); - MOZ_ASSERT(mLoadInfo->GetUsePrivateBrowsing() == (mLoadInfo->GetOriginAttributes().mPrivateBrowsingId != 0), - "PrivateBrowsing mismatch on LoadInfo."); - #ifdef DEBUG CheckPrivateBrowsing(); #endif diff --git a/netwerk/test/unit/test_cacheflags.js b/netwerk/test/unit/test_cacheflags.js index 65fd347fe80a..28c24b14c4ef 100644 --- a/netwerk/test/unit/test_cacheflags.js +++ b/netwerk/test/unit/test_cacheflags.js @@ -1,5 +1,6 @@ Cu.import("resource://testing-common/httpd.js"); Cu.import("resource://gre/modules/NetUtil.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); var httpserver = new HttpServer(); httpserver.start(-1); @@ -23,7 +24,9 @@ function LoadContext(usePrivateBrowsing) { } LoadContext.prototype = { - originAttributes: {}, + originAttributes: { + privateBrowsingId : 0 + }, usePrivateBrowsing: false, // don't bother defining rest of nsILoadContext fields: don't need 'em @@ -38,24 +41,26 @@ LoadContext.prototype = { return this; throw Cr.NS_ERROR_NO_INTERFACE; }, - - originAttributes: {} }; -PrivateBrowsingLoadContext = new LoadContext(true); +var PrivateBrowsingLoadContext = new LoadContext(true); function make_channel(url, flags, usePrivateBrowsing) { var securityFlags = Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL; - if (usePrivateBrowsing) { - securityFlags |= Ci.nsILoadInfo.SEC_FORCE_PRIVATE_BROWSING; - } - var req = NetUtil.newChannel({uri: url, loadUsingSystemPrincipal: true, - securityFlags: securityFlags}); + + var uri = Services.io.newURI(url, null, null); + var principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, + { privateBrowsingId : usePrivateBrowsing ? 1 : 0 }); + + var req = NetUtil.newChannel({uri: uri, + loadingPrincipal: principal, + securityFlags: securityFlags, + contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER}); + req.loadFlags = flags; if (usePrivateBrowsing) { req.notificationCallbacks = PrivateBrowsingLoadContext; } - req.loadInfo.originAttributes = {privateBrowsingId: usePrivateBrowsing ? 1 : 0}; return req; } From 318e608e5789a5fb3bfa0948848c8ec0706b8abd Mon Sep 17 00:00:00 2001 From: Matthew Gregan Date: Tue, 27 Sep 2016 13:09:21 +1300 Subject: [PATCH 076/102] Bug 1305596 - Convert debug-only asserts added in bug 1303247 to release asserts. r=rillian --- media/libstagefright/binding/MP4Metadata.cpp | 35 ++++++++++---------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/media/libstagefright/binding/MP4Metadata.cpp b/media/libstagefright/binding/MP4Metadata.cpp index f4f43b410942..f29ac29c061d 100644 --- a/media/libstagefright/binding/MP4Metadata.cpp +++ b/media/libstagefright/binding/MP4Metadata.cpp @@ -282,30 +282,31 @@ MP4Metadata::GetTrackInfo(mozilla::TrackInfo::TrackType aType, #ifndef RELEASE_BUILD if (mRustTestMode && info) { - MOZ_ASSERT(infoRust); - MOZ_ASSERT(infoRust->mId == info->mId); - MOZ_ASSERT(infoRust->mKind == info->mKind); - MOZ_ASSERT(infoRust->mLabel == info->mLabel); - MOZ_ASSERT(infoRust->mLanguage == info->mLanguage); - MOZ_ASSERT(infoRust->mEnabled == info->mEnabled); - MOZ_ASSERT(infoRust->mTrackId == info->mTrackId); - MOZ_ASSERT(infoRust->mMimeType == info->mMimeType); - MOZ_ASSERT(infoRust->mDuration == info->mDuration); - MOZ_ASSERT(infoRust->mMediaTime == info->mMediaTime); + MOZ_DIAGNOSTIC_ASSERT(infoRust); + MOZ_DIAGNOSTIC_ASSERT(infoRust->mId == info->mId); + MOZ_DIAGNOSTIC_ASSERT(infoRust->mKind == info->mKind); + MOZ_DIAGNOSTIC_ASSERT(infoRust->mLabel == info->mLabel); + MOZ_DIAGNOSTIC_ASSERT(infoRust->mLanguage == info->mLanguage); + MOZ_DIAGNOSTIC_ASSERT(infoRust->mEnabled == info->mEnabled); + MOZ_DIAGNOSTIC_ASSERT(infoRust->mTrackId == info->mTrackId); + MOZ_DIAGNOSTIC_ASSERT(infoRust->mMimeType == info->mMimeType); + MOZ_DIAGNOSTIC_ASSERT(infoRust->mDuration == info->mDuration); + MOZ_DIAGNOSTIC_ASSERT(infoRust->mMediaTime == info->mMediaTime); switch (aType) { case mozilla::TrackInfo::kAudioTrack: { AudioInfo *audioRust = infoRust->GetAsAudioInfo(), *audio = info->GetAsAudioInfo(); - MOZ_ASSERT(audioRust->mRate == audio->mRate); - MOZ_ASSERT(audioRust->mChannels == audio->mChannels); - MOZ_ASSERT(audioRust->mBitDepth == audio->mBitDepth); - //MOZ_ASSERT(audioRust->mProfile == audio->mProfile); - //MOZ_ASSERT(audioRust->mExtendedProfile == audio->mExtendedProfile); + MOZ_DIAGNOSTIC_ASSERT(audioRust->mRate == audio->mRate); + MOZ_DIAGNOSTIC_ASSERT(audioRust->mChannels == audio->mChannels); + MOZ_DIAGNOSTIC_ASSERT(audioRust->mBitDepth == audio->mBitDepth); + // TODO: These fields aren't implemented in the Rust demuxer yet. + //MOZ_DIAGNOSTIC_ASSERT(audioRust->mProfile != audio->mProfile); + //MOZ_DIAGNOSTIC_ASSERT(audioRust->mExtendedProfile != audio->mExtendedProfile); break; } case mozilla::TrackInfo::kVideoTrack: { VideoInfo *videoRust = infoRust->GetAsVideoInfo(), *video = info->GetAsVideoInfo(); - MOZ_ASSERT(videoRust->mDisplay == video->mDisplay); - MOZ_ASSERT(videoRust->mImage == video->mImage); + MOZ_DIAGNOSTIC_ASSERT(videoRust->mDisplay == video->mDisplay); + MOZ_DIAGNOSTIC_ASSERT(videoRust->mImage == video->mImage); break; } default: From de2a95a064ba76a101dd849dae4e0feb45baefdd Mon Sep 17 00:00:00 2001 From: Matthew Gregan Date: Wed, 28 Sep 2016 10:07:47 +1300 Subject: [PATCH 077/102] Bug 1305604 - Convert dashes to underscores in crate name when generating --extern option. r=froydnj --- python/mozbuild/mozbuild/backend/recursivemake.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/mozbuild/mozbuild/backend/recursivemake.py b/python/mozbuild/mozbuild/backend/recursivemake.py index 30ef77284ff4..a681e7a47d01 100644 --- a/python/mozbuild/mozbuild/backend/recursivemake.py +++ b/python/mozbuild/mozbuild/backend/recursivemake.py @@ -1274,7 +1274,7 @@ class RecursiveMakeBackend(CommonBackend): for rlib in rlibs: rlib_relpath = pretty_relpath(rlib) backend_file.write('RUST_PRELINK_FLAGS += --extern %s=%s/%s\n' - % (rlib.basename, rlib_relpath, rlib.import_name)) + % (rlib.basename.replace('-', '_'), rlib_relpath, rlib.import_name)) backend_file.write('RUST_PRELINK_FLAGS += -L %s/%s\n' % (rlib_relpath, rlib.deps_path)) backend_file.write('RUST_PRELINK_DEPS += %s/%s\n' From a026f5edf997e9789704f90e0c8ddc5381287ecd Mon Sep 17 00:00:00 2001 From: Sebastian Hengst Date: Tue, 27 Sep 2016 23:21:47 +0200 Subject: [PATCH 078/102] Backed out changeset 7bcb0c169466 (bug 1305628) for crashing with mozilla::OffTheBooksMutex::Lock. r=backout --- gfx/ipc/RemoteCompositorSession.cpp | 1 - widget/nsBaseWidget.cpp | 16 +++++++--------- widget/windows/InProcessWinCompositorWidget.cpp | 5 ++--- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/gfx/ipc/RemoteCompositorSession.cpp b/gfx/ipc/RemoteCompositorSession.cpp index 8ebcc88e6f84..0ccabaaa7ed8 100644 --- a/gfx/ipc/RemoteCompositorSession.cpp +++ b/gfx/ipc/RemoteCompositorSession.cpp @@ -5,7 +5,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "RemoteCompositorSession.h" -#include "mozilla/VsyncDispatcher.h" #include "mozilla/layers/APZChild.h" #include "mozilla/layers/APZCTreeManagerChild.h" #include "nsBaseWidget.h" diff --git a/widget/nsBaseWidget.cpp b/widget/nsBaseWidget.cpp index c5b5538cfa99..129cd91af61a 100644 --- a/widget/nsBaseWidget.cpp +++ b/widget/nsBaseWidget.cpp @@ -260,15 +260,6 @@ nsBaseWidget::Shutdown() void nsBaseWidget::DestroyCompositor() { - // We release this before releasing the compositor, since it may hold the - // last reference to our ClientLayerManager. ClientLayerManager's dtor can - // trigger a paint, creating a new compositor, and we don't want to re-use - // the old vsync dispatcher. - if (mCompositorVsyncDispatcher) { - mCompositorVsyncDispatcher->Shutdown(); - mCompositorVsyncDispatcher = nullptr; - } - // The compositor shutdown sequence looks like this: // 1. CompositorSession calls CompositorBridgeChild::Destroy. // 2. CompositorBridgeChild synchronously sends WillClose. @@ -293,6 +284,13 @@ void nsBaseWidget::DestroyCompositor() RefPtr session = mCompositorSession.forget(); session->Shutdown(); } + + // Can have base widgets that are things like tooltips + // which don't have CompositorVsyncDispatchers + if (mCompositorVsyncDispatcher) { + mCompositorVsyncDispatcher->Shutdown(); + mCompositorVsyncDispatcher = nullptr; + } } void nsBaseWidget::ReleaseContentController() diff --git a/widget/windows/InProcessWinCompositorWidget.cpp b/widget/windows/InProcessWinCompositorWidget.cpp index 685eaf5ca62c..f88c94ac161d 100644 --- a/widget/windows/InProcessWinCompositorWidget.cpp +++ b/widget/windows/InProcessWinCompositorWidget.cpp @@ -32,9 +32,8 @@ InProcessWinCompositorWidget::RealWidget() void InProcessWinCompositorWidget::ObserveVsync(VsyncObserver* aObserver) { - if (RefPtr cvd = mWindow->GetCompositorVsyncDispatcher()) { - cvd->SetCompositorVsyncObserver(aObserver); - } + RefPtr cvd = mWindow->GetCompositorVsyncDispatcher(); + cvd->SetCompositorVsyncObserver(aObserver); } } // namespace widget From 792cfa85a277afae6de9805a386da2cc74e78236 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Tue, 27 Sep 2016 14:22:25 -0700 Subject: [PATCH 079/102] Bug 1269722 - Add a missing #include for non-unified. r=bustage --HG-- extra : rebase_source : 6eb14e043d0fedfb79bca6e2c8013e8216dd5ac9 --- js/src/vm/Printer.h | 1 + 1 file changed, 1 insertion(+) diff --git a/js/src/vm/Printer.h b/js/src/vm/Printer.h index 0cc19c342fcb..ae70d59fa114 100644 --- a/js/src/vm/Printer.h +++ b/js/src/vm/Printer.h @@ -12,6 +12,7 @@ #include #include #include +#include class JSString; From 2e88e8e508d6879bcfb33487b276bd18d3ebfe00 Mon Sep 17 00:00:00 2001 From: Edwin Flores Date: Tue, 27 Sep 2016 19:52:17 +0100 Subject: [PATCH 080/102] Bug 1306234 - Back out changeset f7aeb4b3ccb1 (bug 1279398) for causing top crashes. r=edwin --HG-- extra : rebase_source : 24aee74e09242f1cae18a1df48654268a2e91769 --- gfx/thebes/gfxASurface.cpp | 2 +- gfx/thebes/gfxASurface.h | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/gfx/thebes/gfxASurface.cpp b/gfx/thebes/gfxASurface.cpp index 18831d8443cb..31f185596507 100644 --- a/gfx/thebes/gfxASurface.cpp +++ b/gfx/thebes/gfxASurface.cpp @@ -171,7 +171,7 @@ gfxASurface::Wrap (cairo_surface_t *csurf, const IntSize& aSize) } #endif else { - MOZ_CRASH("Unknown cairo surface type"); + result = new gfxUnknownSurface(csurf, aSize); } // fprintf(stderr, "New wrapper for %p -> %p\n", csurf, result); diff --git a/gfx/thebes/gfxASurface.h b/gfx/thebes/gfxASurface.h index 3e0818e4532a..ca7535e5607d 100644 --- a/gfx/thebes/gfxASurface.h +++ b/gfx/thebes/gfxASurface.h @@ -183,4 +183,22 @@ protected: bool mSurfaceValid; }; +/** + * An Unknown surface; used to wrap unknown cairo_surface_t returns from cairo + */ +class gfxUnknownSurface : public gfxASurface { +public: + gfxUnknownSurface(cairo_surface_t *surf, const mozilla::gfx::IntSize& aSize) + : mSize(aSize) + { + Init(surf, true); + } + + virtual ~gfxUnknownSurface() { } + virtual const mozilla::gfx::IntSize GetSize() const override { return mSize; } + +private: + mozilla::gfx::IntSize mSize; +}; + #endif /* GFX_ASURFACE_H */ From 705201543914b424a9f4f724d89e1e94eb7f2651 Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Tue, 27 Sep 2016 12:28:57 -0400 Subject: [PATCH 081/102] Bug 1304195 - silence warnings from ScopedXErrorHandler when used off main thread if acknowledged. r=nical MozReview-Commit-ID: 34LaghDR15f --- gfx/gl/GLContextProviderGLX.cpp | 4 ++-- gfx/src/X11Util.cpp | 10 ++++++---- gfx/src/X11Util.h | 14 +++++++++++++- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/gfx/gl/GLContextProviderGLX.cpp b/gfx/gl/GLContextProviderGLX.cpp index 03df3c6d7014..9a1157f330cb 100644 --- a/gfx/gl/GLContextProviderGLX.cpp +++ b/gfx/gl/GLContextProviderGLX.cpp @@ -823,7 +823,7 @@ GLContextGLX::CreateGLContext(CreateContextFlags flags, const SurfaceCaps& caps, RefPtr glContext; bool error; - ScopedXErrorHandler xErrorHandler; + OffMainThreadScopedXErrorHandler xErrorHandler; do { error = false; @@ -1311,7 +1311,7 @@ CreateOffscreenPixmapContext(CreateContextFlags flags, const IntSize& size, int depth; FindVisualAndDepth(display, visid, &visual, &depth); - ScopedXErrorHandler xErrorHandler; + OffMainThreadScopedXErrorHandler xErrorHandler; bool error = false; Drawable drawable; diff --git a/gfx/src/X11Util.cpp b/gfx/src/X11Util.cpp index e1492be54511..7dd02d2fd7a8 100644 --- a/gfx/src/X11Util.cpp +++ b/gfx/src/X11Util.cpp @@ -57,13 +57,15 @@ ScopedXErrorHandler::ErrorHandler(Display *, XErrorEvent *ev) return 0; } -ScopedXErrorHandler::ScopedXErrorHandler() +ScopedXErrorHandler::ScopedXErrorHandler(bool aAllowOffMainThread) { - // Off main thread usage is not safe in general, but OMTC GL layers uses this - // with the main thread blocked, which makes it safe. - NS_WARNING_ASSERTION( + if (!aAllowOffMainThread) { + // Off main thread usage is not safe in general, but OMTC GL layers uses this + // with the main thread blocked, which makes it safe. + NS_WARNING_ASSERTION( NS_IsMainThread(), "ScopedXErrorHandler being called off main thread, may cause issues"); + } // let sXErrorPtr point to this object's mXError object, but don't reset this mXError object! // think of the case of nested ScopedXErrorHandler's. mOldXErrorPtr = sXErrorPtr; diff --git a/gfx/src/X11Util.h b/gfx/src/X11Util.h index dff855ff23f9..e04913342d93 100644 --- a/gfx/src/X11Util.h +++ b/gfx/src/X11Util.h @@ -118,7 +118,10 @@ public: static int ErrorHandler(Display *, XErrorEvent *ev); - ScopedXErrorHandler(); + /** + * @param aAllowOffMainThread whether to warn if used off main thread + */ + explicit ScopedXErrorHandler(bool aAllowOffMainThread = false); ~ScopedXErrorHandler(); @@ -131,6 +134,15 @@ public: bool SyncAndGetError(Display *dpy, XErrorEvent *ev = nullptr); }; +class OffMainThreadScopedXErrorHandler : public ScopedXErrorHandler +{ +public: + OffMainThreadScopedXErrorHandler() + : ScopedXErrorHandler(true) + { + } +}; + } // namespace mozilla #endif // mozilla_X11Util_h From 632d270fe0df43943321f5cd5c7ae79ffd23955b Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Tue, 27 Sep 2016 17:31:13 -0400 Subject: [PATCH 082/102] Bug 1305312 - write putImageData pixels as opaque for opaque canvas. r=jrmuizel MozReview-Commit-ID: 5mVzeNwY28u --- dom/canvas/CanvasRenderingContext2D.cpp | 6 ++++-- dom/canvas/crashtests/1305312-1.html | 5 +++++ dom/canvas/crashtests/crashtests.list | 1 + 3 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 dom/canvas/crashtests/1305312-1.html diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index c7e5122b5a5c..644203797d70 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -5768,6 +5768,8 @@ CanvasRenderingContext2D::PutImageData_explicit(int32_t aX, int32_t aY, uint32_t //uint8_t *src = aArray->Data(); uint8_t *dst = imgsurf->Data(); uint8_t* srcLine = aArray->Data() + copyY * (aW * 4) + copyX * 4; + // For opaque canvases, we must still premultiply the RGB components, but write the alpha as opaque. + uint8_t alphaMask = mOpaque ? 255 : 0; #if 0 printf("PutImageData_explicit: dirty x=%d y=%d w=%d h=%d copy x=%d y=%d w=%d h=%d ext x=%d y=%d w=%d h=%d\n", dirtyRect.x, dirtyRect.y, copyWidth, copyHeight, @@ -5787,9 +5789,9 @@ CanvasRenderingContext2D::PutImageData_explicit(int32_t aX, int32_t aY, uint32_t *dst++ = gfxUtils::sPremultiplyTable[a * 256 + b]; *dst++ = gfxUtils::sPremultiplyTable[a * 256 + g]; *dst++ = gfxUtils::sPremultiplyTable[a * 256 + r]; - *dst++ = a; + *dst++ = a | alphaMask; #else - *dst++ = a; + *dst++ = a | alphaMask; *dst++ = gfxUtils::sPremultiplyTable[a * 256 + r]; *dst++ = gfxUtils::sPremultiplyTable[a * 256 + g]; *dst++ = gfxUtils::sPremultiplyTable[a * 256 + b]; diff --git a/dom/canvas/crashtests/1305312-1.html b/dom/canvas/crashtests/1305312-1.html new file mode 100644 index 000000000000..3bd0b8c00424 --- /dev/null +++ b/dom/canvas/crashtests/1305312-1.html @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/dom/canvas/crashtests/crashtests.list b/dom/canvas/crashtests/crashtests.list index 1960a97fc257..eaf366d9ddb4 100644 --- a/dom/canvas/crashtests/crashtests.list +++ b/dom/canvas/crashtests/crashtests.list @@ -37,4 +37,5 @@ load 1290628-1.html load 1283113-1.html load 1286458-1.html load 1299062-1.html +load 1305312-1.html From 99dc13308fc1f33093e211fa8ac7a8013fdb4144 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Tue, 27 Sep 2016 17:31:59 -0400 Subject: [PATCH 083/102] Backed out changeset 5285464565a8 for landing with the wrong bug number in the commit message. --HG-- extra : rebase_source : 9aff59b0badc1d7fb1a173471fb829f9320e311d --- gfx/thebes/gfxASurface.cpp | 2 +- gfx/thebes/gfxASurface.h | 18 ------------------ 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/gfx/thebes/gfxASurface.cpp b/gfx/thebes/gfxASurface.cpp index 31f185596507..18831d8443cb 100644 --- a/gfx/thebes/gfxASurface.cpp +++ b/gfx/thebes/gfxASurface.cpp @@ -171,7 +171,7 @@ gfxASurface::Wrap (cairo_surface_t *csurf, const IntSize& aSize) } #endif else { - result = new gfxUnknownSurface(csurf, aSize); + MOZ_CRASH("Unknown cairo surface type"); } // fprintf(stderr, "New wrapper for %p -> %p\n", csurf, result); diff --git a/gfx/thebes/gfxASurface.h b/gfx/thebes/gfxASurface.h index ca7535e5607d..3e0818e4532a 100644 --- a/gfx/thebes/gfxASurface.h +++ b/gfx/thebes/gfxASurface.h @@ -183,22 +183,4 @@ protected: bool mSurfaceValid; }; -/** - * An Unknown surface; used to wrap unknown cairo_surface_t returns from cairo - */ -class gfxUnknownSurface : public gfxASurface { -public: - gfxUnknownSurface(cairo_surface_t *surf, const mozilla::gfx::IntSize& aSize) - : mSize(aSize) - { - Init(surf, true); - } - - virtual ~gfxUnknownSurface() { } - virtual const mozilla::gfx::IntSize GetSize() const override { return mSize; } - -private: - mozilla::gfx::IntSize mSize; -}; - #endif /* GFX_ASURFACE_H */ From d6dab74e60457ad247b1e89228365e9f8cd28bf3 Mon Sep 17 00:00:00 2001 From: Edwin Flores Date: Tue, 27 Sep 2016 19:52:17 +0100 Subject: [PATCH 084/102] Bug 1305234 - Back out changeset f7aeb4b3ccb1 (bug 1279398) for causing top crashes. r=edwin DONTBUILD --HG-- extra : rebase_source : 17ccf89223eeca1bc08c3e45ec7e22d3456c2d00 extra : source : 5285464565a804f3766f273b20fb7147f92db53e --- gfx/thebes/gfxASurface.cpp | 2 +- gfx/thebes/gfxASurface.h | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/gfx/thebes/gfxASurface.cpp b/gfx/thebes/gfxASurface.cpp index 18831d8443cb..31f185596507 100644 --- a/gfx/thebes/gfxASurface.cpp +++ b/gfx/thebes/gfxASurface.cpp @@ -171,7 +171,7 @@ gfxASurface::Wrap (cairo_surface_t *csurf, const IntSize& aSize) } #endif else { - MOZ_CRASH("Unknown cairo surface type"); + result = new gfxUnknownSurface(csurf, aSize); } // fprintf(stderr, "New wrapper for %p -> %p\n", csurf, result); diff --git a/gfx/thebes/gfxASurface.h b/gfx/thebes/gfxASurface.h index 3e0818e4532a..ca7535e5607d 100644 --- a/gfx/thebes/gfxASurface.h +++ b/gfx/thebes/gfxASurface.h @@ -183,4 +183,22 @@ protected: bool mSurfaceValid; }; +/** + * An Unknown surface; used to wrap unknown cairo_surface_t returns from cairo + */ +class gfxUnknownSurface : public gfxASurface { +public: + gfxUnknownSurface(cairo_surface_t *surf, const mozilla::gfx::IntSize& aSize) + : mSize(aSize) + { + Init(surf, true); + } + + virtual ~gfxUnknownSurface() { } + virtual const mozilla::gfx::IntSize GetSize() const override { return mSize; } + +private: + mozilla::gfx::IntSize mSize; +}; + #endif /* GFX_ASURFACE_H */ From 69fd23cff2e396eef072b35fa996f1dc4eacb65e Mon Sep 17 00:00:00 2001 From: Geoff Brown Date: Tue, 27 Sep 2016 15:34:28 -0600 Subject: [PATCH 085/102] Bug 1204281 - Adjust chunks and max run time for Android mochitests; r=me --- taskcluster/ci/android-test/tests.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/taskcluster/ci/android-test/tests.yml b/taskcluster/ci/android-test/tests.yml index 5aa2de3474da..24b03be87d0c 100644 --- a/taskcluster/ci/android-test/tests.yml +++ b/taskcluster/ci/android-test/tests.yml @@ -93,13 +93,16 @@ mochitest: suite: mochitest/plain-chunked treeherder-symbol: tc-M() instance-size: xlarge - chunks: 20 + chunks: + by-test-platform: + android-4.3-arm7-api-15/debug: 26 + default: 20 loopback-video: true e10s: false max-run-time: by-test-platform: android-4.3-arm7-api-15/debug: 10800 - default: 3600 + default: 5400 mozharness: script: android_emulator_unittest.py no-read-buildbot-config: true From 1af5239b389e812cb9cc56a7e4b528eef55e4325 Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Tue, 27 Sep 2016 15:15:25 -0700 Subject: [PATCH 086/102] Bug 1283681 - Update list of CPOW-whitelisted add-ons based on new data --- browser/app/profile/firefox.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 9bb75e6e28b2..b3ddb27916d7 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1452,7 +1452,7 @@ pref("dom.ipc.cpows.forbid-unsafe-from-browser", true); pref("dom.ipc.cpows.forbid-cpows-in-compat-addons", true); // ...except for these add-ons: -pref("dom.ipc.cpows.allow-cpows-in-compat-addons", "{b9db16a4-6edc-47ec-a1f4-b86292ed211d},privateTab@infocatcher,mousegesturessuite@lemon_juice.addons.mozilla.org,firegestures@xuldev.org,treestyletab@piro.sakura.ne.jp,{DDC359D1-844A-42a7-9AA1-88A850A938A8},ich@maltegoetz.de,{AE93811A-5C9A-4d34-8462-F7B864FC4696}"); +pref("dom.ipc.cpows.allow-cpows-in-compat-addons", "{b9db16a4-6edc-47ec-a1f4-b86292ed211d},firegestures@xuldev.org,{DDC359D1-844A-42a7-9AA1-88A850A938A8},privateTab@infocatcher,mousegesturessuite@lemon_juice.addons.mozilla.org,treestyletab@piro.sakura.ne.jp,cliqz@cliqz.com,{AE93811A-5C9A-4d34-8462-F7B864FC4696},contextsearch2@lwz.addons.mozilla.org,{EF522540-89F5-46b9-B6FE-1829E2B572C6},{677a8f98-fd64-40b0-a883-b8c95d0cbf17},images@wink.su,fx-devtools,toolkit/require,url_advisor@kaspersky.com,{d10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d},{dc572301-7619-498c-a57d-39143191b318},dta@downthemall.net,{86095750-AD15-46d8-BF32-C0789F7E6A32},screenwise-prod@google.com,{91aa5abe-9de4-4347-b7b5-322c38dd9271},secureLogin@blueimp.net,ich@maltegoetz.de,come.back.block.image.from@cat-in-136.blogspot.com,{7b1bf0b6-a1b9-42b0-b75d-252036438bdc},s3crypto@data,{1e0fd655-5aea-4b4c-a583-f76ef1e3af9c},akahuku.fx.sp@toshiakisp.github.io,{aff87fa2-a58e-4edd-b852-0a20203c1e17},{1018e4d6-728f-4b20-ad56-37578a4de76b},rehostimage@engy.us,lazarus@interclue.com,{b2e69492-2358-071a-7056-24ad0c3defb1},flashstopper@byo.co.il,{e4a8a97b-f2ed-450b-b12d-ee082ba24781},jid1-f3mYMbCpz2AZYl@jetpack,{8c550e28-88c9-4764-bb52-aa489cf2efcd},{37fa1426-b82d-11db-8314-0800200c9a66},{ac2cfa60-bc96-11e0-962b-0800200c9a66},igetter@presenta.net,killspinners@byo.co.il,abhere2@moztw.org,{fc6339b8-9581-4fc7-b824-dffcb091fcb7},wampi@wink.su,backtrack@byalexv.co.uk,Gladiator_X@mail.ru,{73a6fe31-595d-460b-a920-fcc0f8843232},{46551EC9-40F0-4e47-8E18-8E5CF550CFB8},acewebextension_unlisted@acestream.org,@screen_maker,yasearch@yandex.ru,sp@avast.com,s3google@translator,igetterextension@presenta.net,{C1A2A613-35F1-4FCF-B27F-2840527B6556},screenwise-testing@google.com,helper-sig@savefrom.net,browser-loader,ImageSaver@Merci.chao,proxtube@abz.agency,wrc@avast.com,{9AA46F4F-4DC7-4c06-97AF-5035170634FE},jid1-CikLKKPVkw6ipw@jetpack,artur.dubovoy@gmail.com,nlgfeb@nlgfeb.ext,{A065A84F-95B6-433A-A0C8-4C040B77CE8A},fdm_ffext@freedownloadmanager.org"); // Enable e10s hang monitoring (slow script checking and plugin hang // detection). From d6f48852a6fcef2ac2e32af6b142c7156957797b Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Wed, 28 Sep 2016 11:34:48 +1300 Subject: [PATCH 087/102] Bug 1305213 - Make sure the cached CanUseHardwareVideoDecoding value is updated when DeviceMangerDx is initialized. r=dvander --- gfx/thebes/gfxPlatform.cpp | 8 +++++--- gfx/thebes/gfxPlatform.h | 2 +- gfx/thebes/gfxWindowsPlatform.cpp | 6 +++++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 3706356266f4..343ca9fa1d12 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -2098,13 +2098,15 @@ static mozilla::Atomic sLayersAccelerationPrefsInitialized(false); void VideoDecodingFailedChangedCallback(const char* aPref, void*) { sLayersHardwareVideoDecodingFailed = Preferences::GetBool(aPref, false); - gfxPlatform::GetPlatform()->UpdateCanUseHardareVideoDecoding(); + gfxPlatform::GetPlatform()->UpdateCanUseHardwareVideoDecoding(); } void -gfxPlatform::UpdateCanUseHardareVideoDecoding() +gfxPlatform::UpdateCanUseHardwareVideoDecoding() { - gfxVars::SetCanUseHardwareVideoDecoding(CanUseHardwareVideoDecoding()); + if (XRE_IsParentProcess()) { + gfxVars::SetCanUseHardwareVideoDecoding(CanUseHardwareVideoDecoding()); + } } void diff --git a/gfx/thebes/gfxPlatform.h b/gfx/thebes/gfxPlatform.h index 2d630386f7fd..ba4673de94eb 100644 --- a/gfx/thebes/gfxPlatform.h +++ b/gfx/thebes/gfxPlatform.h @@ -456,7 +456,7 @@ public: static bool OffMainThreadCompositingEnabled(); - void UpdateCanUseHardareVideoDecoding(); + void UpdateCanUseHardwareVideoDecoding(); // Returns a prioritized list of all available compositor backends. void GetCompositorBackends(bool useAcceleration, nsTArray& aBackends); diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index 697c90ef0f4e..0bff2a793bff 100755 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -365,6 +365,10 @@ gfxWindowsPlatform::InitAcceleration() DeviceManagerDx::Init(); DeviceManagerD3D9::Init(); + // CanUseHardwareVideoDecoding depends on DeviceManagerDx state, + // so update the cached value now. + UpdateCanUseHardwareVideoDecoding(); + InitializeConfig(); InitializeDevices(); UpdateANGLEConfig(); @@ -2030,7 +2034,7 @@ gfxWindowsPlatform::ImportGPUDeviceData(const mozilla::gfx::GPUDeviceData& aData // CanUseHardwareVideoDecoding depends on d3d11 state, so update // the cached value now. - UpdateCanUseHardareVideoDecoding(); + UpdateCanUseHardwareVideoDecoding(); // For completeness (and messaging in about:support). Content recomputes this // on its own, and we won't use ANGLE in the UI process if we're using a GPU From aa23cf7561e7602077cd17620504798faad644a5 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Wed, 28 Sep 2016 04:44:11 -0400 Subject: [PATCH 088/102] Bug 1305814 - fix -Wreorder warning in MessageChannel; r=billm Initializer lists are supposed to initialize member variables in the order they're listed in the class definition. --- ipc/glue/MessageChannel.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ipc/glue/MessageChannel.cpp b/ipc/glue/MessageChannel.cpp index 49d488a70956..7c266df31fcf 100644 --- a/ipc/glue/MessageChannel.cpp +++ b/ipc/glue/MessageChannel.cpp @@ -484,6 +484,9 @@ MessageChannel::MessageChannel(MessageListener *aListener) mTransactionStack(nullptr), mTimedOutMessageSeqno(0), mTimedOutMessagePriority(0), +#if defined(MOZ_CRASHREPORTER) && defined(OS_WIN) + mPending(AnnotateAllocator(*this)), +#endif mRemoteStackDepthGuess(false), mSawInterruptOutMsg(false), mIsWaitingForIncoming(false), @@ -492,9 +495,6 @@ MessageChannel::MessageChannel(MessageListener *aListener) mFlags(REQUIRE_DEFAULT), mPeerPidSet(false), mPeerPid(-1) -#if defined(MOZ_CRASHREPORTER) && defined(OS_WIN) - , mPending(AnnotateAllocator(*this)) -#endif { MOZ_COUNT_CTOR(ipc::MessageChannel); From e26fb466f232b3d92a6a7df44292df24c3c41e4c Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Tue, 27 Sep 2016 13:49:59 -0700 Subject: [PATCH 089/102] Bug 1304359 - Don't break browser for tabswitch assertions (r=mconley) --- browser/base/content/tabbrowser.xml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index e29eb7231ac4..303a2e702fcc 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -3678,7 +3678,11 @@ assert: function(cond) { if (!cond) { dump("Assertion failure\n" + Error().stack); - throw new Error("Assertion failure"); + + // Don't break a user's browser if an assertion fails. + if (this.tabbrowser.AppConstants.DEBUG) { + throw new Error("Assertion failure"); + } } }, From 6148c4595299b27d33a47a4af2ee050c34901e74 Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Fri, 23 Sep 2016 15:11:43 -0700 Subject: [PATCH 090/102] Bug 1305165 - UpdateDisplayPortMarginsFromPendingMessages should use PCompositorBridge channel (r=kats) --- layout/base/nsLayoutUtils.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 18bda54dadb1..2f39b2d42433 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -108,6 +108,7 @@ #include "nsFrameSelection.h" #include "FrameLayerBuilder.h" #include "mozilla/layers/APZCTreeManager.h" +#include "mozilla/layers/CompositorBridgeChild.h" #include "mozilla/Telemetry.h" #include "mozilla/EventDispatcher.h" #include "mozilla/EventStateManager.h" @@ -9292,10 +9293,11 @@ static void UpdateDisplayPortMarginsForPendingMetrics(FrameMetrics& aMetrics) { } /* static */ void -nsLayoutUtils::UpdateDisplayPortMarginsFromPendingMessages() { +nsLayoutUtils::UpdateDisplayPortMarginsFromPendingMessages() +{ if (mozilla::dom::ContentChild::GetSingleton() && mozilla::dom::ContentChild::GetSingleton()->GetIPCChannel()) { - mozilla::dom::ContentChild::GetSingleton()->GetIPCChannel()->PeekMessages( + CompositorBridgeChild::Get()->GetIPCChannel()->PeekMessages( [](const IPC::Message& aMsg) -> bool { if (aMsg.type() == mozilla::layers::PAPZ::Msg_RequestContentRepaint__ID) { PickleIterator iter(aMsg); From 52de92c14c477f8fcbca5b598b282c7ae515a34b Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Tue, 27 Sep 2016 16:37:07 +1000 Subject: [PATCH 091/102] Bug 1304692 - Make puppet widget get coordinate rounding from parent. r=smaug MozReview-Commit-ID: A3ornUMDmt8 --- dom/ipc/ContentChild.cpp | 5 +++-- dom/ipc/PBrowser.ipdl | 8 +++++++- dom/ipc/TabChild.cpp | 25 +++++++++++++++++++++++-- dom/ipc/TabChild.h | 4 ++++ dom/ipc/TabParent.cpp | 20 +++++++++++++++++--- dom/ipc/TabParent.h | 3 +++ widget/PuppetWidget.cpp | 15 +++++++++++++++ widget/PuppetWidget.h | 6 +++++- 8 files changed, 77 insertions(+), 9 deletions(-) diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index dc5c381ae8d9..1bad3d422221 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -822,14 +822,15 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener, renderFrame = nullptr; } - ShowInfo showInfo(EmptyString(), false, false, true, false, 0, 0); + ShowInfo showInfo(EmptyString(), false, false, true, false, 0, 0, 0); auto* opener = nsPIDOMWindowOuter::From(aParent); nsIDocShell* openerShell; if (opener && (openerShell = opener->GetDocShell())) { nsCOMPtr context = do_QueryInterface(openerShell); showInfo = ShowInfo(EmptyString(), false, context->UsePrivateBrowsing(), true, false, - aTabOpener->mDPI, aTabOpener->mDefaultScale); + aTabOpener->mDPI, aTabOpener->mRounding, + aTabOpener->mDefaultScale); } // Unfortunately we don't get a window unless we've shown the frame. That's diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index 9e76fe9a23ef..d5af87a5aaea 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -101,6 +101,7 @@ struct ShowInfo bool fakeShowInfo; bool isTransparent; float dpi; + int32_t widgetRounding; double defaultScale; }; @@ -375,6 +376,11 @@ parent: */ sync GetDefaultScale() returns (double value); + /** + * Gets the rounding of coordinates in the widget. + */ + sync GetWidgetRounding() returns (int32_t value); + /** * Gets maximum of touch points at current device. */ @@ -793,7 +799,7 @@ child: * value (-1) but in the majority of the cases this saves us from two * sync requests from the child to the parent. */ - async UIResolutionChanged(float dpi, double scale); + async UIResolutionChanged(float dpi, int32_t rounding, double scale); /** * Tell the child that the system theme has changed, and that a repaint diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index bfec7b6eee47..ced61fc55b03 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -541,6 +541,7 @@ TabChild::TabChild(nsIContentChild* aManager, , mDestroyed(false) , mUniqueId(aTabId) , mDPI(0) + , mRounding(0) , mDefaultScale(0) , mIsTransparent(false) , mIPCOpen(false) @@ -1549,6 +1550,7 @@ TabChild::ApplyShowInfo(const ShowInfo& aInfo) } } mDPI = aInfo.dpi(); + mRounding = aInfo.widgetRounding(); mDefaultScale = aInfo.defaultScale(); mIsTransparent = aInfo.isTransparent(); } @@ -2942,6 +2944,22 @@ TabChild::GetDefaultScale(double* aScale) SendGetDefaultScale(aScale); } +void +TabChild::GetWidgetRounding(int32_t* aRounding) +{ + *aRounding = 1; + if (!mRemoteFrame) { + return; + } + if (mRounding > 0) { + *aRounding = mRounding; + return; + } + + // Fallback to a sync call if needed. + SendGetWidgetRounding(aRounding); +} + void TabChild::GetMaxTouchPoints(uint32_t* aTouchPoints) { @@ -3285,12 +3303,15 @@ TabChild::RecvRequestNotifyAfterRemotePaint() } bool -TabChild::RecvUIResolutionChanged(const float& aDpi, const double& aScale) +TabChild::RecvUIResolutionChanged(const float& aDpi, + const int32_t& aRounding, + const double& aScale) { ScreenIntSize oldScreenSize = GetInnerSize(); mDPI = 0; + mRounding = 0; mDefaultScale = 0; - static_cast(mPuppetWidget.get())->UpdateBackingScaleCache(aDpi, aScale); + static_cast(mPuppetWidget.get())->UpdateBackingScaleCache(aDpi, aRounding, aScale); nsCOMPtr document(GetDocument()); nsCOMPtr presShell = document->GetShell(); if (presShell) { diff --git a/dom/ipc/TabChild.h b/dom/ipc/TabChild.h index 8ff3b7c5a5fc..e9e9dd157129 100644 --- a/dom/ipc/TabChild.h +++ b/dom/ipc/TabChild.h @@ -484,6 +484,8 @@ public: void GetDefaultScale(double *aScale); + void GetWidgetRounding(int32_t* aRounding); + bool IsTransparent() const { return mIsTransparent; } void GetMaxTouchPoints(uint32_t* aTouchPoints); @@ -572,6 +574,7 @@ public: } virtual bool RecvUIResolutionChanged(const float& aDpi, + const int32_t& aRounding, const double& aScale) override; virtual bool @@ -777,6 +780,7 @@ private: friend class ContentChild; float mDPI; + int32_t mRounding; double mDefaultScale; bool mIsTransparent; diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 9143b1adf14d..8051435342c1 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -277,6 +277,7 @@ TabParent::TabParent(nsIContentParent* aManager, , mDimensions(0, 0) , mOrientation(0) , mDPI(0) + , mRounding(0) , mDefaultScale(0) , mUpdatedDimensions(false) , mSizeMode(nsSizeMode_Normal) @@ -1030,7 +1031,8 @@ TabParent::UIResolutionChanged() // fails to cache the values, then mDefaultScale.scale might be invalid. // We don't want to send that value to content. Just send -1 for it too in // that case. - Unused << SendUIResolutionChanged(mDPI, mDPI < 0 ? -1.0 : mDefaultScale.scale); + Unused << SendUIResolutionChanged(mDPI, mRounding, + mDPI < 0 ? -1.0 : mDefaultScale.scale); } } @@ -2499,6 +2501,17 @@ TabParent::RecvGetDefaultScale(double* aValue) return true; } +bool +TabParent::RecvGetWidgetRounding(int32_t* aValue) +{ + TryCacheDPIAndScale(); + + MOZ_ASSERT(mRounding > 0, + "Must not ask for rounding before OwnerElement is received!"); + *aValue = mRounding; + return true; +} + bool TabParent::RecvGetMaxTouchPoints(uint32_t* aTouchPoints) { @@ -2766,6 +2779,7 @@ TabParent::TryCacheDPIAndScale() if (widget) { mDPI = widget->GetDPI(); + mRounding = widget->RoundsWidgetCoordinatesTo(); mDefaultScale = widget->GetDefaultScale(); } } @@ -3374,11 +3388,11 @@ TabParent::GetShowInfo() nsContentUtils::IsChromeDoc(mFrameElement->OwnerDoc()) && mFrameElement->HasAttr(kNameSpaceID_None, nsGkAtoms::transparent); return ShowInfo(name, allowFullscreen, isPrivate, false, - isTransparent, mDPI, mDefaultScale.scale); + isTransparent, mDPI, mRounding, mDefaultScale.scale); } return ShowInfo(EmptyString(), false, false, false, - false, mDPI, mDefaultScale.scale); + false, mDPI, mRounding, mDefaultScale.scale); } void diff --git a/dom/ipc/TabParent.h b/dom/ipc/TabParent.h index aff413e2609a..13738229d807 100644 --- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -321,6 +321,8 @@ public: virtual bool RecvGetDefaultScale(double* aValue) override; + virtual bool RecvGetWidgetRounding(int32_t* aValue) override; + virtual bool RecvGetMaxTouchPoints(uint32_t* aTouchPoints) override; virtual bool RecvGetWidgetNativeData(WindowsHandle* aValue) override; @@ -635,6 +637,7 @@ protected: ScreenIntSize mDimensions; ScreenOrientationInternal mOrientation; float mDPI; + int32_t mRounding; CSSToLayoutDeviceScale mDefaultScale; bool mUpdatedDimensions; nsSizeMode mSizeMode; diff --git a/widget/PuppetWidget.cpp b/widget/PuppetWidget.cpp index 967352ffa867..3382a4000e77 100644 --- a/widget/PuppetWidget.cpp +++ b/widget/PuppetWidget.cpp @@ -79,6 +79,7 @@ PuppetWidget::PuppetWidget(TabChild* aTabChild) : mTabChild(aTabChild) , mMemoryPressureObserver(nullptr) , mDPI(-1) + , mRounding(-1) , mDefaultScale(-1) , mCursorHotspotX(0) , mCursorHotspotY(0) @@ -1194,6 +1195,20 @@ PuppetWidget::GetDefaultScaleInternal() return mDefaultScale; } +int32_t +PuppetWidget::RoundsWidgetCoordinatesTo() +{ + if (mRounding < 0) { + if (mTabChild) { + mTabChild->GetWidgetRounding(&mRounding); + } else { + mRounding = 1; + } + } + + return mRounding; +} + void* PuppetWidget::GetNativeData(uint32_t aDataType) { diff --git a/widget/PuppetWidget.h b/widget/PuppetWidget.h index dc70c7647f1b..5d0581356c62 100644 --- a/widget/PuppetWidget.h +++ b/widget/PuppetWidget.h @@ -135,6 +135,8 @@ public: virtual LayoutDeviceIntPoint WidgetToScreenOffset() override { return LayoutDeviceIntPoint::FromUnknownPoint(GetWindowPosition() + GetChromeDimensions()); } + int32_t RoundsWidgetCoordinatesTo() override; + void InitEvent(WidgetGUIEvent& aEvent, LayoutDeviceIntPoint* aPoint = nullptr); @@ -202,9 +204,10 @@ public: virtual TabChild* GetOwningTabChild() override { return mTabChild; } - void UpdateBackingScaleCache(float aDpi, double aScale) + void UpdateBackingScaleCache(float aDpi, int32_t aRounding, double aScale) { mDPI = aDpi; + mRounding = aRounding; mDefaultScale = aScale; } @@ -358,6 +361,7 @@ private: // The DPI of the screen corresponding to this widget float mDPI; + int32_t mRounding; double mDefaultScale; // Precomputed answers for ExecuteNativeKeyBinding From a1db43df464dcf9d1c69294ff5fa050b37f8944f Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Wed, 28 Sep 2016 12:11:18 +1000 Subject: [PATCH 092/102] Bug 1279814 followup - Add crashtest for this bug. r=jfkthame MozReview-Commit-ID: HViGSGNbscY --HG-- extra : source : 0706234a33fd0d5b519700f051554bdcda3dd558 --- layout/generic/crashtests/1279814.html | 35 +++++++++++++++++++++++ layout/generic/crashtests/crashtests.list | 1 + 2 files changed, 36 insertions(+) create mode 100644 layout/generic/crashtests/1279814.html diff --git a/layout/generic/crashtests/1279814.html b/layout/generic/crashtests/1279814.html new file mode 100644 index 000000000000..71a9a6e3b416 --- /dev/null +++ b/layout/generic/crashtests/1279814.html @@ -0,0 +1,35 @@ + +⁦⁧⁦⁧⁦⁧⁦⁧ +⁦⁧⁦⁧⁦⁧⁦⁧ +⁦⁧⁦⁧⁦⁧⁦⁧ +⁦⁧⁦⁧⁦⁧⁦⁧ +⁦⁧⁦⁧⁦⁧⁦⁧ +⁦⁧⁦⁧⁦⁧⁦⁧ +⁦⁧⁦⁧⁦⁧⁦⁧ +⁦⁧⁦⁧⁦⁧⁦⁧ +⁦⁧⁦⁧⁦⁧⁦⁧ +⁦⁧⁦⁧⁦⁧⁦⁧ +⁦⁧⁦⁧⁦⁧⁦⁧ +⁦⁧⁦⁧⁦⁧⁦⁧ +⁦⁧⁦⁧⁦⁧⁦⁧ +⁦⁧⁦⁧⁦⁧⁦⁧ +⁦⁧⁦⁧⁦⁧⁦⁧ +⁦⁧⁦⁧⁦⁧⁦⁧ + +⁩⁩⁩⁩⁩⁩⁩⁩ +⁩⁩⁩⁩⁩⁩⁩⁩ +⁩⁩⁩⁩⁩⁩⁩⁩ +⁩⁩⁩⁩⁩⁩⁩⁩ +⁩⁩⁩⁩⁩⁩⁩⁩ +⁩⁩⁩⁩⁩⁩⁩⁩ +⁩⁩⁩⁩⁩⁩⁩⁩ +⁩⁩⁩⁩⁩⁩⁩⁩ + +⁦⁧⁦⁧⁦⁧⁦⁧ +⁦⁧⁦⁧⁦⁧⁦⁧ +⁦⁧⁦⁧⁦⁧⁦⁧ +⁦⁧⁦⁧⁦⁧⁦⁧ +⁦⁧⁦⁧⁦⁧⁦⁧ +⁦⁧⁦⁧⁦⁧⁦⁧ +⁦⁧⁦⁧⁦⁧⁦⁧ +⁦⁧⁦⁧⁦⁧⁦⁧ diff --git a/layout/generic/crashtests/crashtests.list b/layout/generic/crashtests/crashtests.list index 01e70ed16bbb..96099570be05 100644 --- a/layout/generic/crashtests/crashtests.list +++ b/layout/generic/crashtests/crashtests.list @@ -631,6 +631,7 @@ asserts(2) load 1272983-1.html # bug 586628 asserts(2) load 1272983-2.html # bug 586628 load 1275059.html load 1278007.html +load 1279814.html load large-border-radius-dashed.html load large-border-radius-dashed2.html load large-border-radius-dotted.html From fb058e68f63db2c7ed9a12fa57e12873b4096676 Mon Sep 17 00:00:00 2001 From: Thomas Wisniewski Date: Thu, 15 Sep 2016 14:19:23 -0400 Subject: [PATCH 093/102] Bug 1303121 - Do not fire one last progress event on XHR errors, to match a spec change. r=annevk --- dom/base/test/test_bug435425.html | 22 +++---- dom/xhr/XMLHttpRequestMainThread.cpp | 7 +-- ...progress-events-response-data-gzip.htm.ini | 5 -- .../tests/XMLHttpRequest/abort-after-send.htm | 39 +++++------- .../XMLHttpRequest/abort-during-upload.htm | 2 +- .../XMLHttpRequest/abort-event-order.htm | 2 +- .../XMLHttpRequest/event-timeout-order.htm | 2 +- .../progress-events-response-data-gzip.htm | 28 +++++---- .../resources/xmlhttprequest-event-order.js | 59 +++++++++++++++++-- .../send-response-event-order.htm | 37 ++---------- 10 files changed, 107 insertions(+), 96 deletions(-) delete mode 100644 testing/web-platform/meta/XMLHttpRequest/progress-events-response-data-gzip.htm.ini diff --git a/dom/base/test/test_bug435425.html b/dom/base/test/test_bug435425.html index 0e4e3a4ebd28..828931d67d17 100644 --- a/dom/base/test/test_bug435425.html +++ b/dom/base/test/test_bug435425.html @@ -217,7 +217,7 @@ var tests = {target: XHR, type: "loadend", optional: false}]}, { method: "GET", withUpload: none, testAbort: true, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, - {target: XHR, type: "progress", optional: false}, + {target: XHR, type: "progress", optional: true}, {target: XHR, type: "abort", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "GET", withUpload: none, testAbort: false, testRedirectError: true, testNetworkError: false, @@ -236,7 +236,7 @@ var tests = {target: XHR, type: "loadend", optional: false}]}, { method: "GET", withUpload: small, testAbort: true, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, - {target: XHR, type: "progress", optional: false}, + {target: XHR, type: "progress", optional: true}, {target: XHR, type: "abort", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "GET", withUpload: small, testAbort: false, testRedirectError: true, testNetworkError: false, @@ -255,7 +255,7 @@ var tests = {target: XHR, type: "loadend", optional: false}]}, { method: "GET", withUpload: mid, testAbort: true, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, - {target: XHR, type: "progress", optional: false}, + {target: XHR, type: "progress", optional: true}, {target: XHR, type: "abort", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "GET", withUpload: mid, testAbort: false, testRedirectError: true, testNetworkError: false, @@ -274,7 +274,7 @@ var tests = {target: XHR, type: "loadend", optional: false}]}, { method: "GET", withUpload: large, testAbort: true, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, - {target: XHR, type: "progress", optional: false}, + {target: XHR, type: "progress", optional: true}, {target: XHR, type: "abort", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "GET", withUpload: large, testAbort: false, testRedirectError: true, testNetworkError: false, @@ -293,7 +293,7 @@ var tests = {target: XHR, type: "loadend", optional: false}]}, { method: "POST", withUpload: none, testAbort: true, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, - {target: XHR, type: "progress", optional: false}, + {target: XHR, type: "progress", optional: true}, {target: XHR, type: "abort", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "POST", withUpload: none, testAbort: false, testRedirectError: true, testNetworkError: false, @@ -317,10 +317,10 @@ var tests = { method: "POST", withUpload: small, testAbort: true, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, {target: UPLOAD, type: "loadstart", optional: false}, - {target: UPLOAD, type: "progress", optional: false}, + {target: UPLOAD, type: "progress", optional: true}, {target: UPLOAD, type: "abort", optional: false}, {target: UPLOAD, type: "loadend", optional: false}, - {target: XHR, type: "progress", optional: false}, + {target: XHR, type: "progress", optional: true}, {target: XHR, type: "abort", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "POST", withUpload: small, testAbort: false, testRedirectError: true, testNetworkError: false, @@ -351,10 +351,10 @@ var tests = { method: "POST", withUpload: mid, testAbort: true, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, {target: UPLOAD, type: "loadstart", optional: false}, - {target: UPLOAD, type: "progress", optional: false}, + {target: UPLOAD, type: "progress", optional: true}, {target: UPLOAD, type: "abort", optional: false}, {target: UPLOAD, type: "loadend", optional: false}, - {target: XHR, type: "progress", optional: false}, + {target: XHR, type: "progress", optional: true}, {target: XHR, type: "abort", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "POST", withUpload: mid, testAbort: false, testRedirectError: true, testNetworkError: false, @@ -385,10 +385,10 @@ var tests = { method: "POST", withUpload: large, testAbort: true, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, {target: UPLOAD, type: "loadstart", optional: false}, - {target: UPLOAD, type: "progress", optional: false}, + {target: UPLOAD, type: "progress", optional: true}, {target: UPLOAD, type: "abort", optional: false}, {target: UPLOAD, type: "loadend", optional: false}, - {target: XHR, type: "progress", optional: false}, + {target: XHR, type: "progress", optional: true}, {target: XHR, type: "abort", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "POST", withUpload: large, testAbort: false, testRedirectError: true, testNetworkError: false, diff --git a/dom/xhr/XMLHttpRequestMainThread.cpp b/dom/xhr/XMLHttpRequestMainThread.cpp index 496ee55c0937..99162070b899 100644 --- a/dom/xhr/XMLHttpRequestMainThread.cpp +++ b/dom/xhr/XMLHttpRequestMainThread.cpp @@ -1038,10 +1038,8 @@ XMLHttpRequestMainThread::CloseRequestWithError(const ProgressEventType aType) if (!mFlagSyncLooping) { if (mUpload && !mUploadComplete) { mUploadComplete = true; - DispatchProgressEvent(mUpload, ProgressEventType::progress, 0, 0); DispatchProgressEvent(mUpload, aType, 0, 0); } - DispatchProgressEvent(this, ProgressEventType::progress, 0, 0); DispatchProgressEvent(this, aType, 0, 0); } } @@ -2184,10 +2182,9 @@ XMLHttpRequestMainThread::ChangeStateToDone() // Per spec, fire readystatechange=4/done before final error events. ChangeState(State::done, true); - // Per spec, if we failed in the upload phase, fire a final progress, error, - // and loadend event for the upload after readystatechange=4/done. + // Per spec, if we failed in the upload phase, fire a final error + // and loadend events for the upload after readystatechange=4/done. if (!mFlagSynchronous && mUpload && !mUploadComplete) { - DispatchProgressEvent(mUpload, ProgressEventType::progress, 0, 0); DispatchProgressEvent(mUpload, ProgressEventType::error, 0, 0); } diff --git a/testing/web-platform/meta/XMLHttpRequest/progress-events-response-data-gzip.htm.ini b/testing/web-platform/meta/XMLHttpRequest/progress-events-response-data-gzip.htm.ini deleted file mode 100644 index 5adf572e37d3..000000000000 --- a/testing/web-platform/meta/XMLHttpRequest/progress-events-response-data-gzip.htm.ini +++ /dev/null @@ -1,5 +0,0 @@ -[progress-events-response-data-gzip.htm] - type: testharness - [XMLHttpRequest: progress events and GZIP encoding] - expected: FAIL - diff --git a/testing/web-platform/tests/XMLHttpRequest/abort-after-send.htm b/testing/web-platform/tests/XMLHttpRequest/abort-after-send.htm index c4885c9911b0..523a0d616b64 100644 --- a/testing/web-platform/tests/XMLHttpRequest/abort-after-send.htm +++ b/testing/web-platform/tests/XMLHttpRequest/abort-after-send.htm @@ -4,6 +4,7 @@ XMLHttpRequest: abort() after send() + @@ -19,36 +20,26 @@ var test = async_test() test.step(function() { var client = new XMLHttpRequest(), - control_flag = false, - result = [], - expected = [1, 4, 'progress', 'abort', 'loadend'] // open() -> 1, abort() -> 4 - client.onreadystatechange = function() { - test.step(function() { - result.push(client.readyState) - if(client.readyState == 4) { - control_flag = true - assert_equals(client.responseXML, null) - assert_equals(client.responseText, "") - assert_equals(client.status, 0) - assert_equals(client.statusText, "") - assert_equals(client.getAllResponseHeaders(), "") - assert_equals(client.getResponseHeader('Content-Type'), null) - } - }) - } + control_flag = false; + prepare_xhr_for_event_order_test(client); + client.addEventListener("readystatechange", test.step_func(function() { + if(client.readyState == 4) { + control_flag = true + assert_equals(client.responseXML, null) + assert_equals(client.responseText, "") + assert_equals(client.status, 0) + assert_equals(client.statusText, "") + assert_equals(client.getAllResponseHeaders(), "") + assert_equals(client.getResponseHeader('Content-Type'), null) + } + })) client.open("GET", "resources/well-formed.xml", true) client.send(null) - client.addEventListener('progress', logEvt) - client.addEventListener('abort', logEvt) - client.addEventListener('loadend', logEvt) client.abort() assert_true(control_flag) assert_equals(client.readyState, 0) - assert_array_equals(result, expected) + assert_xhr_event_order_matches([1, "loadstart(0,0,false)", 4, "abort(0,0,false)", "loadend(0,0,false)"]) test.done() - function logEvt (e) { - result.push(e.type) - } }) diff --git a/testing/web-platform/tests/XMLHttpRequest/abort-during-upload.htm b/testing/web-platform/tests/XMLHttpRequest/abort-during-upload.htm index 766dcc4693d8..9fbc8b9bbb47 100644 --- a/testing/web-platform/tests/XMLHttpRequest/abort-during-upload.htm +++ b/testing/web-platform/tests/XMLHttpRequest/abort-during-upload.htm @@ -18,7 +18,7 @@ client.open("POST", "resources/delay.py?ms=1000") client.addEventListener("loadend", function(e) { test.step(function() { - assert_xhr_event_order_matches([1, "loadstart(0,0,false)", "upload.loadstart(0,9999,true)", 4, "upload.progress(0,0,false)", "upload.abort(0,0,false)", "upload.loadend(0,0,false)", "progress(0,0,false)", "abort(0,0,false)", "loadend(0,0,false)"]); + assert_xhr_event_order_matches([1, "loadstart(0,0,false)", "upload.loadstart(0,9999,true)", 4, "upload.abort(0,0,false)", "upload.loadend(0,0,false)", "abort(0,0,false)", "loadend(0,0,false)"]); test.done() }) }); diff --git a/testing/web-platform/tests/XMLHttpRequest/abort-event-order.htm b/testing/web-platform/tests/XMLHttpRequest/abort-event-order.htm index cb405a71accf..f05c20628c4a 100644 --- a/testing/web-platform/tests/XMLHttpRequest/abort-event-order.htm +++ b/testing/web-platform/tests/XMLHttpRequest/abort-event-order.htm @@ -37,7 +37,7 @@ { test.step(function() { - assert_xhr_event_order_matches([1, "loadstart(0,0,false)", 4, "upload.progress(0,0,false)", "upload.abort(0,0,false)", "upload.loadend(0,0,false)", "progress(0,0,false)", "abort(0,0,false)", "loadend(0,0,false)"]); + assert_xhr_event_order_matches([1, "loadstart(0,0,false)", 4, "upload.abort(0,0,false)", "upload.loadend(0,0,false)", "abort(0,0,false)", "loadend(0,0,false)"]); assert_equals(xhr.readyState, 0, 'state should be UNSENT'); test.done(); diff --git a/testing/web-platform/tests/XMLHttpRequest/event-timeout-order.htm b/testing/web-platform/tests/XMLHttpRequest/event-timeout-order.htm index 1d9ba31d6e06..7376ca2f8b14 100644 --- a/testing/web-platform/tests/XMLHttpRequest/event-timeout-order.htm +++ b/testing/web-platform/tests/XMLHttpRequest/event-timeout-order.htm @@ -20,7 +20,7 @@ prepare_xhr_for_event_order_test(xhr); xhr.addEventListener("loadend", function() { test.step(function() { - assert_xhr_event_order_matches([1, "loadstart(0,0,false)", "upload.loadstart(0,12,true)", 4, "upload.progress(0,0,false)", "upload.timeout(0,0,false)", "upload.loadend(0,0,false)", "progress(0,0,false)", "timeout(0,0,false)", "loadend(0,0,false)"]); + assert_xhr_event_order_matches([1, "loadstart(0,0,false)", "upload.loadstart(0,12,true)", 4, "upload.timeout(0,0,false)", "upload.loadend(0,0,false)", "timeout(0,0,false)", "loadend(0,0,false)"]); test.done(); }); }); diff --git a/testing/web-platform/tests/XMLHttpRequest/progress-events-response-data-gzip.htm b/testing/web-platform/tests/XMLHttpRequest/progress-events-response-data-gzip.htm index dc166a2396a4..058064636d43 100644 --- a/testing/web-platform/tests/XMLHttpRequest/progress-events-response-data-gzip.htm +++ b/testing/web-platform/tests/XMLHttpRequest/progress-events-response-data-gzip.htm @@ -36,17 +36,20 @@ * If lengthComputable is true: * Event.total must match Content-length header - * event.loaded should be a smaller number while resource is loading - and match Content-length when loading is finished - * Setting event.loaded to equal event.total for each progress event if the - resource is not fully downloaded would be cheating + * event.loaded must only ever increase in progress events + (and may never repeat its value). + * event.loaded must never exceed the Content-length. * If lengthComputable is false: * event.total should be 0 + * event.loaded must only ever increase in progress events + (and may never repeat its value). * event.loaded should be the length of the decompressed content, i.e. bigger than Content-length header value when finished loading */ + var lastTotal; + var lastLoaded = -1; client.addEventListener('loadend', test.step_func(function(e){ var len = parseInt(client.getResponseHeader('content-length'), 10) if(e.lengthComputable){ @@ -59,14 +62,17 @@ test.done(); }), false) client.addEventListener('progress', test.step_func(function(e){ - if(e.lengthComputable && e.total && e.loaded && e.target.readyState < 4){ - assert_not_equals(e.total, e.loaded, 'total should not equal loaded while download/decode is incomplete') - // We should only do this assertation once - // it's theoretically possible that all the data would get in - // and a progress event fire before the readyState switches from 3 to 4 - - // in this case we might report bogus and random failures. Better to remove the event listener again.. - client.removeEventListener('progress', arguments.callee, false); + if(lastTotal === undefined){ + lastTotal = e.total; } + if(e.lengthComputable && e.total && e.loaded){ + assert_equals(e.total, lastTotal, 'event.total should remain invariant') + assert_less_than_equal(e.loaded, lastTotal, 'event.loaded should not exceed content-length') + }else{ + assert_equals(e.total, 0, 'event.total should be 0') + } + assert_greater_than(e.loaded, lastLoaded, 'event.loaded should only ever increase') + lastLoaded = e.loaded; }), false) // image.gif is 165375 bytes compressed. Sending 45000 bytes at a time with 1 second delay will load it in 4 seconds client.open("GET", "resources/image.gif?pipe=gzip|trickle(45000:d1:r2)", true) diff --git a/testing/web-platform/tests/XMLHttpRequest/resources/xmlhttprequest-event-order.js b/testing/web-platform/tests/XMLHttpRequest/resources/xmlhttprequest-event-order.js index 820f9ee22143..77fc0e784ef9 100644 --- a/testing/web-platform/tests/XMLHttpRequest/resources/xmlhttprequest-event-order.js +++ b/testing/web-platform/tests/XMLHttpRequest/resources/xmlhttprequest-event-order.js @@ -21,13 +21,60 @@ } } + function getNextEvent(arr) { + var eventStr = arr.shift(); + + // we can only handle strings, numbers (readystates) and undefined + if (eventStr === undefined) { + return event; + } + if (typeof eventStr !== "string") { + if (Number.isInteger(eventStr)) { + eventStr = "readystatechange(" + eventStr + ")"; + } else { + throw "Test error: unexpected event type " + eventStr; + } + } + + // parse out the general type, loaded and total values + var type = eventStr.type = eventStr.split("(")[0].split(".").pop(); + eventStr.mayFollowOptionalProgressEvents = type == "progress" || + type == "load" || type == "abort" || type == "error"; + var loadedAndTotal = eventStr.match(/\((\d)+,(\d)+/); + if (loadedAndTotal) { + eventStr.loaded = parseInt(loadedAndTotal[0]); + eventStr.total = parseInt(loadedAndTotal[1]); + } + + return eventStr; + } + global.assert_xhr_event_order_matches = function(expected) { - try { - assert_array_equals(recorded_xhr_events, expected); - } catch(e) { - e.message += "\nRecorded events were:" + recorded_xhr_events.join(", "); - e.message += "\nExpected events were:" + expected.join(", "); - throw e; + var recorded = recorded_xhr_events; + var lastRecordedLoaded = -1; + + while(expected.length && recorded.length) { + var currentExpected = getNextEvent(expected), + currentRecorded = getNextEvent(recorded); + + // skip to the last progress event if we've hit one + while (recorded.length && currentRecorded.type == "progress") { + assert_greater(currentRecorded.loaded, lastRecordedLoaded, + "progress event 'loaded' values must only increase"); + lastRecordedLoaded = currentRecorded.loaded; + currentRecorded = getNextEvent(recorded); + } + if (currentRecorded.type == "loadstart") { + lastRecordedLoaded = -1; + } + + assert_equals(currentRecorded, currentExpected); + } + if (recorded.length) { + throw "\nUnexpected extra events: " + recorded.join(", "); + } + if (expected.length) { + throw "\nExpected more events: " + expected.join(", "); } } }(this)); diff --git a/testing/web-platform/tests/XMLHttpRequest/send-response-event-order.htm b/testing/web-platform/tests/XMLHttpRequest/send-response-event-order.htm index 64dfaa670f82..041cb23c6ea8 100644 --- a/testing/web-platform/tests/XMLHttpRequest/send-response-event-order.htm +++ b/testing/web-platform/tests/XMLHttpRequest/send-response-event-order.htm @@ -12,6 +12,7 @@ + XMLHttpRequest: The send() method: event order when synchronous flag is unset @@ -24,38 +25,12 @@ test.step(function() { var xhr = new XMLHttpRequest(); - var expect = ["loadstart", "upload.loadstart", "upload.progress", "upload.load", "upload.loadend", "progress", 4, "load", "loadend"]; - var actual = []; + prepare_xhr_for_event_order_test(xhr); - xhr.onreadystatechange = function() - { - test.step(function() - { - if (xhr.readyState == 4) - { - actual.push(xhr.readyState); - } - }); - }; - - xhr.onloadstart = function(e){ actual.push(e.type); }; - xhr.onload = function(e){ actual.push(e.type); }; - xhr.onloadend = function(e){ actual.push(e.type); VerifyResult()}; - xhr.onprogress = function(e){ actual.push(e.type);}; - - xhr.upload.onloadstart = function(e){ actual.push("upload." + e.type); }; - xhr.upload.onload = function(e){ actual.push("upload." + e.type); }; - xhr.upload.onloadend = function(e){ actual.push("upload." + e.type);}; - xhr.upload.onprogress = function(e){ actual.push("upload." + e.type);}; - - function VerifyResult() - { - test.step(function() - { - assert_array_equals(actual, expect); - test.done(); - }); - }; + xhr.addEventListener("loadend", test.step_func(function() { + assert_xhr_event_order_matches([1, "loadstart(0,0,false)", "upload.loadstart(0,12,true)", "upload.progress(12,12,true)", "upload.load(12,12,true)", "upload.loadend(12,12,true)", 2, 3, "progress(12,12,true)", 4, "load(12,12,true)", "loadend(12,12,true)"]); + test.done(); + })); xhr.open("POST", "./resources/content.py", true); xhr.send("Test Message"); From 1748bfae57f2a5ff0ebe8fa8d3f73b726c0f821a Mon Sep 17 00:00:00 2001 From: David Parks Date: Sat, 24 Sep 2016 02:54:12 -0700 Subject: [PATCH 094/102] Bug 1269114 - [x86_64] Last picked directory not saved when using Flash Player uploader. r=jimm Adds a couple of registry paths to the broker's ALLOW policy. --- .../win/src/sandboxbroker/sandboxBroker.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp b/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp index f9c1e45a5644..58c205076a44 100644 --- a/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp +++ b/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp @@ -311,6 +311,20 @@ SandboxBroker::SetSecurityLevelForPluginProcess(int32_t aSandboxLevel) SANDBOX_ENSURE_SUCCESS(result, "With these static arguments AddRule should never fail, what happened?"); + // These register keys are used by the file-browser dialog box. They + // remember the most-recently-used folders. + result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY, + sandbox::TargetPolicy::REG_ALLOW_ANY, + L"HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\OpenSavePidlMRU\\*"); + SANDBOX_ENSURE_SUCCESS(result, + "With these static arguments AddRule should never fail, what happened?"); + + result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY, + sandbox::TargetPolicy::REG_ALLOW_ANY, + L"HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\LastVisitedPidlMRULegacy\\*"); + SANDBOX_ENSURE_SUCCESS(result, + "With these static arguments AddRule should never fail, what happened?"); + return true; } From f40bbc42f7934551509eec77b41bc8df10d7cfff Mon Sep 17 00:00:00 2001 From: Chris Pearce Date: Tue, 27 Sep 2016 15:01:06 +1300 Subject: [PATCH 095/102] Bug 1305552 - Add telemetry to track uses of MediaKeySession.generateRequest. r=francois,gerald This allows us to track how often EME CDMs are used, rather than just created. The telemetry I added in bug 1304207 is reports whenever a CDM is created, but some sites, such as the Shaka Player demo site, create CDMs without using them, so that telemetry isn't a great measure in helping us detect when CDMs aren't being used. Whereas the telemetry added here will report when the CDMs are used to negotiate a license, i.e. when the CDMs are actually being used. MozReview-Commit-ID: ExMIcIIBvS1 --- dom/media/eme/EMEUtils.cpp | 13 ++++++++++++ dom/media/eme/EMEUtils.h | 10 +++++++++ dom/media/eme/MediaKeySession.cpp | 3 +++ dom/media/eme/MediaKeys.cpp | 22 +------------------- toolkit/components/telemetry/Histograms.json | 9 ++++++++ 5 files changed, 36 insertions(+), 21 deletions(-) diff --git a/dom/media/eme/EMEUtils.cpp b/dom/media/eme/EMEUtils.cpp index 3600de750734..ece3636bd662 100644 --- a/dom/media/eme/EMEUtils.cpp +++ b/dom/media/eme/EMEUtils.cpp @@ -154,4 +154,17 @@ IsClearkeyKeySystem(const nsAString& aKeySystem) return !CompareUTF8toUTF16(kEMEKeySystemClearkey, aKeySystem); } +CDMType +ToCDMTypeTelemetryEnum(const nsString& aKeySystem) +{ + if (!CompareUTF8toUTF16(kEMEKeySystemWidevine, aKeySystem)) { + return CDMType::eWidevine; + } else if (!CompareUTF8toUTF16(kEMEKeySystemClearkey, aKeySystem)) { + return CDMType::eClearKey; + } else if (!CompareUTF8toUTF16(kEMEKeySystemPrimetime, aKeySystem)) { + return CDMType::ePrimetime; + } + return CDMType::eUnknown; +} + } // namespace mozilla diff --git a/dom/media/eme/EMEUtils.h b/dom/media/eme/EMEUtils.h index f21e3b1563a2..bbeaf1226cfa 100644 --- a/dom/media/eme/EMEUtils.h +++ b/dom/media/eme/EMEUtils.h @@ -106,6 +106,16 @@ KeySystemToGMPName(const nsAString& aKeySystem); bool IsClearkeyKeySystem(const nsAString& aKeySystem); +enum CDMType { + eClearKey = 0, + ePrimetime = 1, + eWidevine = 2, + eUnknown = 3 +}; + +CDMType +ToCDMTypeTelemetryEnum(const nsString& aKeySystem); + } // namespace mozilla #endif // EME_LOG_H_ diff --git a/dom/media/eme/MediaKeySession.cpp b/dom/media/eme/MediaKeySession.cpp index e4f472a2cf01..103c77e64fce 100644 --- a/dom/media/eme/MediaKeySession.cpp +++ b/dom/media/eme/MediaKeySession.cpp @@ -199,6 +199,9 @@ MediaKeySession::GenerateRequest(const nsAString& aInitDataType, return promise.forget(); } + Telemetry::Accumulate(Telemetry::VIDEO_CDM_GENERATE_REQUEST_CALLED, + ToCDMTypeTelemetryEnum(mKeySystem)); + // Convert initData to base64 for easier logging. // Note: CreateSession() Move()s the data out of the array, so we have // to copy it here. diff --git a/dom/media/eme/MediaKeys.cpp b/dom/media/eme/MediaKeys.cpp index b972ffaa4c8b..a7a24c824c80 100644 --- a/dom/media/eme/MediaKeys.cpp +++ b/dom/media/eme/MediaKeys.cpp @@ -401,26 +401,6 @@ MediaKeys::Init(ErrorResult& aRv) return promise.forget(); } -enum CDMCreatedType { - eClearKey = 0, - ePrimetime = 1, - eWidevine = 2, - eUnknown = 3 -}; - -static CDMCreatedType -ToCDMCreatedTelemetryEnum(const nsString& aKeySystem) -{ - if (!CompareUTF8toUTF16(kEMEKeySystemWidevine, aKeySystem)) { - return CDMCreatedType::eWidevine; - } else if (!CompareUTF8toUTF16(kEMEKeySystemClearkey, aKeySystem)) { - return CDMCreatedType::eClearKey; - } else if (!CompareUTF8toUTF16(kEMEKeySystemPrimetime, aKeySystem)) { - return CDMCreatedType::ePrimetime; - } - return CDMCreatedType::eUnknown; -} - void MediaKeys::OnCDMCreated(PromiseId aId, const nsACString& aNodeId, const uint32_t aPluginId) { @@ -440,7 +420,7 @@ MediaKeys::OnCDMCreated(PromiseId aId, const nsACString& aNodeId, const uint32_t mKeySystem, MediaKeySystemStatus::Cdm_created); - Telemetry::Accumulate(Telemetry::VIDEO_CDM_CREATED, ToCDMCreatedTelemetryEnum(mKeySystem)); + Telemetry::Accumulate(Telemetry::VIDEO_CDM_CREATED, ToCDMTypeTelemetryEnum(mKeySystem)); } already_AddRefed diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 4382d649d8b4..e9190548719f 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -8716,6 +8716,15 @@ "description": "Note the type of CDM (0=ClearKey, 1=Primetime, 2=Widevine, 3=unknown) every time we successfully instantiate an EME MediaKeys object.", "releaseChannelCollection": "opt-out" }, + "VIDEO_CDM_GENERATE_REQUEST_CALLED": { + "alert_emails": ["cpearce@mozilla.com"], + "expires_in_version": "58", + "bug_numbers": [1305552], + "kind": "enumerated", + "n_values": 6, + "description": "Note the type of CDM (0=ClearKey, 1=Primetime, 2=Widevine, 3=unknown) every time we call MediaKeySession.generateRequest().", + "releaseChannelCollection": "opt-out" + }, "MEDIA_CODEC_USED": { "alert_emails": ["cpearce@mozilla.com"], "expires_in_version": "never", From fe7b5b55fe7c0870b8bb5986b751731ab9188f14 Mon Sep 17 00:00:00 2001 From: Chris Pearce Date: Wed, 28 Sep 2016 13:34:57 +1300 Subject: [PATCH 096/102] Bug 1300069 - Consider a media encrypted if it contains a track with crypto metadata, rather than only if the media contains encryption init data. r=jya Some encrypted MP4 streams don't contain PSSH boxes in their MOOV boxes, but they still have tracks with valid TENC boxes which we still parse. So we need to consider media encrypted if any of its tracks have crypto meta data, rather than only if the media has crypto init data. The WebM demuxer's crypto init data is all the tracks' crypto meta data, so WebM isn't broken by this change. MozReview-Commit-ID: 1qOi4uTtCE3 --HG-- extra : amend_source : 0f266976a3d65fb8dc720cd40d70bd6da1712420 --- dom/media/MediaFormatReader.cpp | 11 +++++++---- dom/media/MediaFormatReader.h | 10 +++------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp index 103fc3f077af..3c410224181f 100644 --- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -72,7 +72,6 @@ MediaFormatReader::MediaFormatReader(AbstractMediaDecoder* aDecoder, , mPreviousDecodedKeyframeTime_us(sNoPreviousDecodedKeyframe) , mLayersBackendType(aLayersBackend) , mInitDone(false) - , mIsEncrypted(false) , mTrackDemuxersMayBlock(false) , mDemuxOnly(false) , mSeekScheduled(false) @@ -337,9 +336,6 @@ MediaFormatReader::OnDemuxerInitDone(nsresult) } UniquePtr crypto = mDemuxer->GetCrypto(); - - mIsEncrypted = crypto && crypto->IsEncrypted(); - if (mDecoder && crypto && crypto->IsEncrypted()) { #ifdef MOZ_EME // Try and dispatch 'encrypted'. Won't go if ready state still HAVE_NOTHING. @@ -375,6 +371,13 @@ MediaFormatReader::OnDemuxerInitDone(nsresult) mMetadataPromise.Resolve(metadata, __func__); } +bool +MediaFormatReader::IsEncrypted() const +{ + return (HasAudio() && mInfo.mAudio.mCrypto.mValid) || + (HasVideo() && mInfo.mVideo.mCrypto.mValid); +} + void MediaFormatReader::OnDemuxerInitFailed(const MediaResult& aError) { diff --git a/dom/media/MediaFormatReader.h b/dom/media/MediaFormatReader.h index 64646ef28dc4..afc90cffa989 100644 --- a/dom/media/MediaFormatReader.h +++ b/dom/media/MediaFormatReader.h @@ -105,8 +105,8 @@ public: private: - bool HasVideo() { return mVideo.mTrackDemuxer; } - bool HasAudio() { return mAudio.mTrackDemuxer; } + bool HasVideo() const { return mVideo.mTrackDemuxer; } + bool HasAudio() const { return mAudio.mTrackDemuxer; } bool IsWaitingOnCDMResource(); @@ -528,11 +528,7 @@ private: // True if we've read the streams' metadata. bool mInitDone; MozPromiseHolder mMetadataPromise; - bool IsEncrypted() - { - return mIsEncrypted; - } - bool mIsEncrypted; + bool IsEncrypted() const; // Set to true if any of our track buffers may be blocking. bool mTrackDemuxersMayBlock; From 22b3d811556aab4f87ffd2308fd07efdfbcb4567 Mon Sep 17 00:00:00 2001 From: Chris Pearce Date: Wed, 28 Sep 2016 13:45:25 +1300 Subject: [PATCH 097/102] Bug 1300069 - Remove TrackBuffersManager::mIsEncrypted. r=jya It's write only, so there's no point storing this, and it's not accurate anyway, as it's actually tracking whether there's encrypted init data in the media, not whether its got encrypted tracks. MozReview-Commit-ID: 78iFUyXwRBV --HG-- extra : rebase_source : f500b90d32da042a550172128a4c79c142048a98 extra : amend_source : c4e31f686e2c0f2c400225919c45c3a530373a8c --- dom/media/mediasource/TrackBuffersManager.cpp | 1 - dom/media/mediasource/TrackBuffersManager.h | 1 - 2 files changed, 2 deletions(-) diff --git a/dom/media/mediasource/TrackBuffersManager.cpp b/dom/media/mediasource/TrackBuffersManager.cpp index 32b84c8bc33f..50ead759a487 100644 --- a/dom/media/mediasource/TrackBuffersManager.cpp +++ b/dom/media/mediasource/TrackBuffersManager.cpp @@ -1075,7 +1075,6 @@ TrackBuffersManager::OnDemuxerInitDone(nsresult) // We clear our crypto init data array, so the MediaFormatReader will // not emit an encrypted event for the same init data again. info.mCrypto.mInitDatas.Clear(); - mEncrypted = true; } { diff --git a/dom/media/mediasource/TrackBuffersManager.h b/dom/media/mediasource/TrackBuffersManager.h index 455e20288268..bbaf8411768f 100644 --- a/dom/media/mediasource/TrackBuffersManager.h +++ b/dom/media/mediasource/TrackBuffersManager.h @@ -240,7 +240,6 @@ private: void OnDemuxerInitFailed(const MediaResult& aFailure); void OnDemuxerResetDone(nsresult); MozPromiseRequestHolder mDemuxerInitRequest; - bool mEncrypted; void OnDemuxFailed(TrackType aTrack, const MediaResult& aError); void DoDemuxVideo(); From 556a8f6ea1f4452ba81593e37f43685e3841d69d Mon Sep 17 00:00:00 2001 From: Phil Ringnalda Date: Tue, 27 Sep 2016 19:49:17 -0700 Subject: [PATCH 098/102] Backed out 3 changesets (bug 1301301) for crashing Backed out changeset da70c5abd73a (bug 1301301) Backed out changeset 6186eae0c2b7 (bug 1301301) Backed out changeset 45fb9c1ce63a (bug 1301301) --- dom/workers/RuntimeService.cpp | 10 +++ js/xpconnect/src/XPCJSContext.cpp | 2 - xpcom/base/CycleCollectedJSContext.cpp | 107 +++++-------------------- xpcom/base/CycleCollectedJSContext.h | 13 +-- 4 files changed, 31 insertions(+), 101 deletions(-) diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index f14177acab0f..cd7c0d18d7c1 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -1099,6 +1099,16 @@ public: { } + virtual void + BeginCycleCollectionCallback() override + { + } + + virtual void + EndCycleCollectionCallback(CycleCollectorResults &aResults) override + { + } + void DispatchDeferredDeletion(bool aContinuation, bool aPurge) override { diff --git a/js/xpconnect/src/XPCJSContext.cpp b/js/xpconnect/src/XPCJSContext.cpp index 1fbe657387b8..909e54b8e028 100644 --- a/js/xpconnect/src/XPCJSContext.cpp +++ b/js/xpconnect/src/XPCJSContext.cpp @@ -665,7 +665,6 @@ XPCJSContext::PrepareForForgetSkippable() void XPCJSContext::BeginCycleCollectionCallback() { - CycleCollectedJSContext::BeginCycleCollectionCallback(); nsJSContext::BeginCycleCollectionCallback(); nsCOMPtr obs = mozilla::services::GetObserverService(); @@ -677,7 +676,6 @@ XPCJSContext::BeginCycleCollectionCallback() void XPCJSContext::EndCycleCollectionCallback(CycleCollectorResults& aResults) { - CycleCollectedJSContext::EndCycleCollectionCallback(aResults); nsJSContext::EndCycleCollectionCallback(aResults); nsCOMPtr obs = mozilla::services::GetObserverService(); diff --git a/xpcom/base/CycleCollectedJSContext.cpp b/xpcom/base/CycleCollectedJSContext.cpp index b5f4a13230ca..93b0dc3d839f 100644 --- a/xpcom/base/CycleCollectedJSContext.cpp +++ b/xpcom/base/CycleCollectedJSContext.cpp @@ -127,29 +127,11 @@ public: } // namespace mozilla -struct CCJSTracer : public JS::CallbackTracer +struct NoteWeakMapChildrenTracer : public JS::CallbackTracer { -protected: - CCJSTracer(CycleCollectedJSContext* aCx, - WeakMapTraceKind aWeakTraceKind = TraceWeakMapValues) - : JS::CallbackTracer(aCx->Context(), aWeakTraceKind) - , mCx(aCx) - {} - -public: - void TraceChildren(JS::GCCellPtr aThing) - { - mCx->TraceJSChildren(this, aThing); - } - - CycleCollectedJSContext* mCx; -}; - -struct NoteWeakMapChildrenTracer : public CCJSTracer -{ - NoteWeakMapChildrenTracer(CycleCollectedJSContext* aCx, + NoteWeakMapChildrenTracer(JSContext* aCx, nsCycleCollectionNoteRootCallback& aCb) - : CCJSTracer(aCx), mCb(aCb), mTracedAny(false), mMap(nullptr), + : JS::CallbackTracer(aCx), mCb(aCb), mTracedAny(false), mMap(nullptr), mKey(nullptr), mKeyDelegate(nullptr) { } @@ -176,15 +158,14 @@ NoteWeakMapChildrenTracer::onChild(const JS::GCCellPtr& aThing) mCb.NoteWeakMapping(mMap, mKey, mKeyDelegate, aThing); mTracedAny = true; } else { - TraceChildren(aThing); + JS::TraceChildren(this, aThing); } } struct NoteWeakMapsTracer : public js::WeakMapTracer { - NoteWeakMapsTracer(CycleCollectedJSContext* aCx, - nsCycleCollectionNoteRootCallback& aCccb) - : js::WeakMapTracer(aCx->Context()), mCb(aCccb), mChildTracer(aCx, aCccb) + NoteWeakMapsTracer(JSContext* aCx, nsCycleCollectionNoteRootCallback& aCccb) + : js::WeakMapTracer(aCx), mCb(aCccb), mChildTracer(aCx, aCccb) { } void trace(JSObject* aMap, JS::GCCellPtr aKey, JS::GCCellPtr aValue) override; @@ -232,7 +213,7 @@ NoteWeakMapsTracer::trace(JSObject* aMap, JS::GCCellPtr aKey, mChildTracer.mKeyDelegate = kdelegate; if (!aValue.is()) { - mChildTracer.TraceChildren(aValue); + JS::TraceChildren(&mChildTracer, aValue); } // The delegate could hold alive the key, so report something to the CC @@ -343,13 +324,12 @@ JSZoneParticipant::Traverse(void* aPtr, nsCycleCollectionTraversalCallback& aCb) return NS_OK; } -struct TraversalTracer : public CCJSTracer +struct TraversalTracer : public JS::CallbackTracer { - TraversalTracer(CycleCollectedJSContext* aCx, - nsCycleCollectionTraversalCallback& aCb) - : CCJSTracer(aCx, DoNotTraceWeakMaps) - , mCb(aCb) - {} + TraversalTracer(JSContext* aCx, nsCycleCollectionTraversalCallback& aCb) + : JS::CallbackTracer(aCx, DoNotTraceWeakMaps), mCb(aCb) + { + } void onChild(const JS::GCCellPtr& aThing) override; nsCycleCollectionTraversalCallback& mCb; }; @@ -386,7 +366,7 @@ TraversalTracer::onChild(const JS::GCCellPtr& aThing) // be traced. JS_TraceObjectGroupCycleCollectorChildren(this, aThing); } else if (!aThing.is()) { - TraceChildren(aThing); + JS::TraceChildren(this, aThing); } } @@ -462,10 +442,6 @@ CycleCollectedJSContext::CycleCollectedJSContext() , mDisableMicroTaskCheckpoint(false) , mOutOfMemoryState(OOMState::OK) , mLargeAllocationFailureState(OOMState::OK) -#ifdef DEBUG - , mNumTraversedGCThings(0) - , mNumTraceChildren(0) -#endif // DEBUG { nsCOMPtr thread = do_GetCurrentThread(); mOwningThread = thread.forget().downcast().take(); @@ -654,11 +630,11 @@ CycleCollectedJSContext::DescribeGCThing(bool aIsMarked, JS::GCCellPtr aThing, void CycleCollectedJSContext::NoteGCThingJSChildren(JS::GCCellPtr aThing, - nsCycleCollectionTraversalCallback& aCb) + nsCycleCollectionTraversalCallback& aCb) const { MOZ_ASSERT(mJSContext); - TraversalTracer trc(this, aCb); - trc.TraceChildren(aThing); + TraversalTracer trc(mJSContext, aCb); + JS::TraceChildren(&trc, aThing); } void @@ -715,10 +691,6 @@ CycleCollectedJSContext::TraverseGCThing(TraverseSelect aTs, JS::GCCellPtr aThin return; } -#ifdef DEBUG - ++mNumTraversedGCThings; -#endif - if (aTs == TRAVERSE_FULL) { NoteGCThingJSChildren(aThing, aCb); } @@ -761,7 +733,7 @@ CycleCollectedJSContext::TraverseZone(JS::Zone* aZone, * iterate over. Edges between compartments in the same zone will add * unnecessary loop edges to the graph (bug 842137). */ - TraversalTracer trc(this, aCb); + TraversalTracer trc(mJSContext, aCb); js::VisitGrayWrapperTargets(aZone, NoteJSChildGrayWrapperShim, &trc); /* @@ -1240,7 +1212,7 @@ CycleCollectedJSContext::TraverseRoots(nsCycleCollectionNoteRootCallback& aCb) TraverseNativeRoots(aCb); - NoteWeakMapsTracer trc(this, aCb); + NoteWeakMapsTracer trc(mJSContext, aCb); js::TraceWeakMaps(&trc); return NS_OK; @@ -1358,40 +1330,6 @@ CycleCollectedJSContext::DumpJSHeap(FILE* aFile) js::DumpHeap(Context(), aFile, js::CollectNurseryBeforeDump); } -void -CycleCollectedJSContext::BeginCycleCollectionCallback() -{ -#ifdef DEBUG - mNumTraversedGCThings = 0; - mNumTraceChildren = 0; -#endif -} - -void -CycleCollectedJSContext::EndCycleCollectionCallback(CycleCollectorResults& aResults) -{ -#ifdef DEBUG - - // GC things that the cycle collector calls Traverse on (ie things - // in the CC graph) will also get JS::TraceChildren() called on - // them. If a child of a GC thing in the CC graph does not have an - // AddToCCKind(), then the CC calls JS::TraceChildren() on it - // without adding it to the graph. If there are many such objects - // that are referred to by many objects in the CC graph, then the CC - // can spend a lot of time in JS::TraceChildren(). If you add a new - // TraceKind and are hitting this assertion, adding it to - // AddToCCKind might help. (The check is not done for small CC - // graphs to avoid noise.) - if (mNumTraceChildren > 1000 && mNumTraversedGCThings > 0) { - double traceRatio = ((double)mNumTraceChildren) / ((double)mNumTraversedGCThings); - MOZ_ASSERT(traceRatio < 2.2, "Excessive calls to JS::TraceChildren by the cycle collector"); - } - - mNumTraversedGCThings = 0; - mNumTraceChildren = 0; -#endif -} - void CycleCollectedJSContext::ProcessStableStateQueue() { @@ -1731,15 +1669,6 @@ CycleCollectedJSContext::OnLargeAllocationFailure() AnnotateAndSetOutOfMemory(&mLargeAllocationFailureState, OOMState::Reported); } -void -CycleCollectedJSContext::TraceJSChildren(JSTracer* aTrc, JS::GCCellPtr aThing) -{ -#ifdef DEBUG - ++mNumTraceChildren; -#endif // DEBUG - JS::TraceChildren(aTrc, aThing); -} - void CycleCollectedJSContext::PrepareWaitingZonesForGC() { diff --git a/xpcom/base/CycleCollectedJSContext.h b/xpcom/base/CycleCollectedJSContext.h index 5cc0026d214b..9415634b8951 100644 --- a/xpcom/base/CycleCollectedJSContext.h +++ b/xpcom/base/CycleCollectedJSContext.h @@ -176,7 +176,7 @@ private: void NoteGCThingJSChildren(JS::GCCellPtr aThing, - nsCycleCollectionTraversalCallback& aCb); + nsCycleCollectionTraversalCallback& aCb) const; void NoteGCThingXPCOMChildren(const js::Class* aClasp, JSObject* aObj, @@ -321,8 +321,8 @@ public: void DumpJSHeap(FILE* aFile); virtual void PrepareForForgetSkippable() = 0; - virtual void BeginCycleCollectionCallback(); - virtual void EndCycleCollectionCallback(CycleCollectorResults& aResults); + virtual void BeginCycleCollectionCallback() = 0; + virtual void EndCycleCollectionCallback(CycleCollectorResults& aResults) = 0; virtual void DispatchDeferredDeletion(bool aContinuation, bool aPurge = false) = 0; JSContext* Context() const @@ -395,8 +395,6 @@ public: mZonesWaitingForGC.PutEntry(aZone); } - void TraceJSChildren(JSTracer* aTrc, JS::GCCellPtr aThing); - // Prepare any zones for GC that have been passed to AddZoneWaitingForGC() // since the last GC or since the last call to PrepareWaitingZonesForGC(), // whichever was most recent. If there were no such zones, prepare for a @@ -478,11 +476,6 @@ private: void invoke(JS::HandleObject scope, Closure& closure) override; }; EnvironmentPreparer mEnvironmentPreparer; - -#ifdef DEBUG - uint32_t mNumTraversedGCThings; - uint32_t mNumTraceChildren; -#endif // DEBUG }; void TraceScriptHolder(nsISupports* aHolder, JSTracer* aTracer); From 07037f896bf7e5f929a0b58e52ef3624413592d0 Mon Sep 17 00:00:00 2001 From: Alexandre Lissy Date: Tue, 27 Sep 2016 10:46:41 +0200 Subject: [PATCH 099/102] Bug 1305655 - Decouple Gonk TextureForwarder and CompositableForwarder (followup bug 1281456) r=nical MozReview-Commit-ID: 1sUiqnFEPdx --- dom/canvas/WebGLContext.cpp | 2 +- dom/media/platforms/gonk/GonkVideoDecoderManager.cpp | 6 +++--- gfx/gl/SurfaceTypes.cpp | 2 +- gfx/gl/SurfaceTypes.h | 4 ++-- gfx/layers/GrallocImages.cpp | 4 ++-- gfx/layers/GrallocImages.h | 2 +- gfx/layers/client/TextureClient.cpp | 2 +- gfx/layers/client/TextureClient.h | 1 + gfx/layers/ipc/ImageBridgeChild.cpp | 4 ++-- gfx/layers/opengl/GrallocTextureClient.cpp | 7 ++----- gfx/layers/opengl/GrallocTextureClient.h | 1 + widget/gonk/nativewindow/GonkBufferQueueJB.cpp | 2 +- widget/gonk/nativewindow/GonkBufferQueueKK.cpp | 2 +- .../GonkBufferQueueLL/GonkBufferQueueProducer.cpp | 2 +- 14 files changed, 20 insertions(+), 21 deletions(-) diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp index f61cb3b85141..87ede3fcaad0 100644 --- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -569,7 +569,7 @@ BaseCaps(const WebGLContextOptions& options, WebGLContext* webgl) if (!forwarder) break; - baseCaps.surfaceAllocator = static_cast(forwarder); + baseCaps.surfaceAllocator = forwarder->GetTextureForwarder(); } while (false); #endif diff --git a/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp b/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp index 06e0cb298462..0c7b3b6af95f 100644 --- a/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp +++ b/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp @@ -52,7 +52,7 @@ public: , mGrallocFormat(aGrallocFormat) {} - already_AddRefed Allocate(TextureForwarder* aAllocator) override + already_AddRefed Allocate(KnowsCompositor* aAllocator) override { uint32_t usage = android::GraphicBuffer::USAGE_SW_READ_OFTEN | android::GraphicBuffer::USAGE_SW_WRITE_OFTEN | @@ -60,7 +60,7 @@ public: GrallocTextureData* texData = GrallocTextureData::Create(mSize, mGrallocFormat, gfx::BackendType::NONE, - usage, aAllocator); + usage, aAllocator->GetTextureForwarder()); if (!texData) { return nullptr; } @@ -69,7 +69,7 @@ public: return nullptr; } RefPtr textureClient = - TextureClient::CreateWithData(texData, TextureFlags::DEALLOCATE_CLIENT, aAllocator); + TextureClient::CreateWithData(texData, TextureFlags::DEALLOCATE_CLIENT, aAllocator->GetTextureForwarder()); return textureClient.forget(); } diff --git a/gfx/gl/SurfaceTypes.cpp b/gfx/gl/SurfaceTypes.cpp index bdaebb5384f1..9c3e8a2e140f 100644 --- a/gfx/gl/SurfaceTypes.cpp +++ b/gfx/gl/SurfaceTypes.cpp @@ -5,7 +5,7 @@ #include "SurfaceTypes.h" -#include "mozilla/layers/ISurfaceAllocator.h" +#include "mozilla/layers/TextureForwarder.h" namespace mozilla { namespace gl { diff --git a/gfx/gl/SurfaceTypes.h b/gfx/gl/SurfaceTypes.h index b3b9a127ac4d..aae21e0a9f73 100644 --- a/gfx/gl/SurfaceTypes.h +++ b/gfx/gl/SurfaceTypes.h @@ -12,7 +12,7 @@ namespace mozilla { namespace layers { -class ISurfaceAllocator; +class LayersIPCChannel; } // namespace layers namespace gl { @@ -29,7 +29,7 @@ struct SurfaceCaps final // The surface allocator that we want to create this // for. May be null. - RefPtr surfaceAllocator; + RefPtr surfaceAllocator; SurfaceCaps(); SurfaceCaps(const SurfaceCaps& other); diff --git a/gfx/layers/GrallocImages.cpp b/gfx/layers/GrallocImages.cpp index 909fd0a71a3a..ed18d8b56d39 100644 --- a/gfx/layers/GrallocImages.cpp +++ b/gfx/layers/GrallocImages.cpp @@ -73,7 +73,7 @@ GrallocImage::SetData(const Data& aData) return false; } - RefPtr allocator = ImageBridgeChild::GetSingleton(); + RefPtr allocator = ImageBridgeChild::GetSingleton(); GrallocTextureData* texData = GrallocTextureData::Create(mData.mYSize, HAL_PIXEL_FORMAT_YV12, gfx::BackendType::NONE, GraphicBuffer::USAGE_SW_READ_OFTEN | @@ -469,7 +469,7 @@ GrallocImage::GetNativeBuffer() } TextureClient* -GrallocImage::GetTextureClient(TextureForwarder* aForwarder) +GrallocImage::GetTextureClient(KnowsCompositor* aForwarder) { return mTextureClient; } diff --git a/gfx/layers/GrallocImages.h b/gfx/layers/GrallocImages.h index 8d6e4a47146f..22b4bdc9b883 100644 --- a/gfx/layers/GrallocImages.h +++ b/gfx/layers/GrallocImages.h @@ -93,7 +93,7 @@ public: virtual bool IsValid() { return !!mTextureClient; } - virtual TextureClient* GetTextureClient(TextureForwarder* aForwarder) override; + virtual TextureClient* GetTextureClient(KnowsCompositor* aForwarder) override; virtual GrallocImage* AsGrallocImage() override { diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp index 0a9a29d39a71..a3b9092a3a6c 100644 --- a/gfx/layers/client/TextureClient.cpp +++ b/gfx/layers/client/TextureClient.cpp @@ -1132,7 +1132,7 @@ TextureClient::CreateForDrawing(TextureForwarder* aAllocator, #endif #ifdef MOZ_WIDGET_GONK - if (!data) { + if (!data && aSize.width <= aMaxTextureSize && aSize.height <= aMaxTextureSize) { data = GrallocTextureData::CreateForDrawing(aSize, aFormat, moz2DBackend, aAllocator); } diff --git a/gfx/layers/client/TextureClient.h b/gfx/layers/client/TextureClient.h index 308d2cef2532..f8cce039a8a7 100644 --- a/gfx/layers/client/TextureClient.h +++ b/gfx/layers/client/TextureClient.h @@ -21,6 +21,7 @@ #include "mozilla/ipc/Shmem.h" // for Shmem #include "mozilla/layers/AtomicRefCountedWithFinalize.h" #include "mozilla/layers/CompositorTypes.h" // for TextureFlags, etc +#include "mozilla/layers/ISurfaceAllocator.h" #include "mozilla/layers/LayersTypes.h" #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor #include "mozilla/mozalloc.h" // for operator delete diff --git a/gfx/layers/ipc/ImageBridgeChild.cpp b/gfx/layers/ipc/ImageBridgeChild.cpp index 8f4ef09e5ed7..c82c5d92bf5b 100644 --- a/gfx/layers/ipc/ImageBridgeChild.cpp +++ b/gfx/layers/ipc/ImageBridgeChild.cpp @@ -335,9 +335,9 @@ ImageBridgeChild::NotifyNotUsedToNonRecycle(uint64_t aTextureId, uint64_t aTrans // Release TextureClient on allocator's message loop. RefPtr task = MakeAndAddRef(client); - RefPtr allocator = client->GetAllocator(); + RefPtr allocator = client->GetAllocator(); client = nullptr; - allocator->AsClientAllocator()->GetMessageLoop()->PostTask(task.forget()); + allocator->GetMessageLoop()->PostTask(task.forget()); #else NS_RUNTIMEABORT("not reached"); #endif diff --git a/gfx/layers/opengl/GrallocTextureClient.cpp b/gfx/layers/opengl/GrallocTextureClient.cpp index e01c137e2808..93a20d969fc5 100644 --- a/gfx/layers/opengl/GrallocTextureClient.cpp +++ b/gfx/layers/opengl/GrallocTextureClient.cpp @@ -8,7 +8,7 @@ #include "mozilla/gfx/2D.h" #include "mozilla/layers/AsyncTransactionTracker.h" // for AsyncTransactionTracker #include "mozilla/layers/GrallocTextureClient.h" -#include "mozilla/layers/CompositableForwarder.h" +#include "mozilla/layers/TextureForwarder.h" #include "mozilla/layers/ISurfaceAllocator.h" #include "mozilla/layers/ShadowLayerUtilsGralloc.h" #include "mozilla/layers/SharedBufferManagerChild.h" @@ -295,10 +295,6 @@ GrallocTextureData::Create(gfx::IntSize aSize, AndroidFormat aAndroidFormat, if (!aAllocator || !aAllocator->IPCOpen()) { return nullptr; } - int32_t maxSize = aAllocator->AsClientAllocator()->GetMaxTextureSize(); - if (aSize.width > maxSize || aSize.height > maxSize) { - return nullptr; - } gfx::SurfaceFormat format; switch (aAndroidFormat) { case android::PIXEL_FORMAT_RGBA_8888: @@ -447,6 +443,7 @@ GrallocTextureData::TextureClientFromSharedSurface(gl::SharedSurface* abstractSu TextureData* GrallocTextureData::CreateSimilar(LayersIPCChannel* aAllocator, + LayersBackend aLayersBackend, TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const { diff --git a/gfx/layers/opengl/GrallocTextureClient.h b/gfx/layers/opengl/GrallocTextureClient.h index fe4c36d2a348..f728e560ff45 100644 --- a/gfx/layers/opengl/GrallocTextureClient.h +++ b/gfx/layers/opengl/GrallocTextureClient.h @@ -75,6 +75,7 @@ public: virtual TextureData* CreateSimilar(LayersIPCChannel* aAllocator, + LayersBackend aLayersBackend, TextureFlags aFlags = TextureFlags::DEFAULT, TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const override; diff --git a/widget/gonk/nativewindow/GonkBufferQueueJB.cpp b/widget/gonk/nativewindow/GonkBufferQueueJB.cpp index c353546a07cf..81502f81eecd 100644 --- a/widget/gonk/nativewindow/GonkBufferQueueJB.cpp +++ b/widget/gonk/nativewindow/GonkBufferQueueJB.cpp @@ -424,7 +424,7 @@ status_t GonkBufferQueue::dequeueBuffer(int *outBuf, sp* outFence, if (returnFlags & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) { usage |= GraphicBuffer::USAGE_HW_TEXTURE; - RefPtr allocator = ImageBridgeChild::GetSingleton(); + RefPtr allocator = ImageBridgeChild::GetSingleton(); GrallocTextureData* texData = GrallocTextureData::Create(IntSize(w,h), format, gfx::BackendType::NONE, usage, allocator); diff --git a/widget/gonk/nativewindow/GonkBufferQueueKK.cpp b/widget/gonk/nativewindow/GonkBufferQueueKK.cpp index 379ae4c7f66e..0c5cdfeb9f40 100644 --- a/widget/gonk/nativewindow/GonkBufferQueueKK.cpp +++ b/widget/gonk/nativewindow/GonkBufferQueueKK.cpp @@ -443,7 +443,7 @@ status_t GonkBufferQueue::dequeueBuffer(int *outBuf, sp* outFence, bool a if (returnFlags & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) { - RefPtr allocator = ImageBridgeChild::GetSingleton(); + RefPtr allocator = ImageBridgeChild::GetSingleton(); usage |= GraphicBuffer::USAGE_HW_TEXTURE; GrallocTextureData* texData = GrallocTextureData::Create(IntSize(w, h), format, gfx::BackendType::NONE, usage, diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.cpp index 3dcf6c321b76..d3436756fb86 100644 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.cpp +++ b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.cpp @@ -342,7 +342,7 @@ status_t GonkBufferQueueProducer::dequeueBuffer(int *outSlot, } // Autolock scope if (returnFlags & BUFFER_NEEDS_REALLOCATION) { - RefPtr allocator = ImageBridgeChild::GetSingleton(); + RefPtr allocator = ImageBridgeChild::GetSingleton(); usage |= GraphicBuffer::USAGE_HW_TEXTURE; GrallocTextureData* texData = GrallocTextureData::Create(IntSize(width,height), format, gfx::BackendType::NONE, From fd9e045dcb4cd1a84e65579d83e5f691cb048ff9 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Wed, 28 Sep 2016 14:12:54 +0900 Subject: [PATCH 100/102] Bug 1304970 - Check encoding of js.msg-like files. r=jandem,gps --- config/check_js_msg_encoding.py | 63 +++++++++++++++++++++++++++++++++ dom/bindings/Errors.msg | 2 +- js/src/Makefile.in | 5 ++- testing/mach_commands.py | 6 +++- 4 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 config/check_js_msg_encoding.py diff --git a/config/check_js_msg_encoding.py b/config/check_js_msg_encoding.py new file mode 100644 index 000000000000..9c6b739d402f --- /dev/null +++ b/config/check_js_msg_encoding.py @@ -0,0 +1,63 @@ +# vim: set ts=8 sts=4 et sw=4 tw=99: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#---------------------------------------------------------------------------- +# This script checks encoding of the files that define JSErrorFormatStrings. +# +# JSErrorFormatString.format member should be in ASCII encoding. +#---------------------------------------------------------------------------- + +from __future__ import print_function + +import os +import sys +from check_utils import get_all_toplevel_filenames + +scriptname = os.path.basename(__file__); +expected_encoding = 'ascii' + +# The following files don't define JSErrorFormatString. +ignore_files = [ + 'dom/base/domerr.msg', + 'js/xpconnect/src/xpc.msg', +] + +def log_pass(filename, text): + print('TEST-PASS | {} | {} | {}'.format(scriptname, filename, text)) + +def log_fail(filename, text): + print('TEST-UNEXPECTED-FAIL | {} | {} | {}'.format(scriptname, filename, + text)) + +def check_single_file(filename): + with open(filename, 'rb') as f: + data = f.read() + try: + data.decode(expected_encoding) + except: + log_fail(filename, 'not in {} encoding'.format(expected_encoding)) + + log_pass(filename, 'ok') + return True + +def check_files(): + result = True + + for filename in get_all_toplevel_filenames(): + if filename.endswith('.msg'): + if filename not in ignore_files: + if not check_single_file(filename): + result = False + + return result + +def main(): + if not check_files(): + sys.exit(1) + + sys.exit(0) + +if __name__ == '__main__': + main() diff --git a/dom/bindings/Errors.msg b/dom/bindings/Errors.msg index 0ef297a03597..047bc8101975 100644 --- a/dom/bindings/Errors.msg +++ b/dom/bindings/Errors.msg @@ -94,7 +94,7 @@ MSG_DEF(MSG_SW_INSTALL_ERROR, 2, JSEXN_TYPEERR, "ServiceWorker script at {0} for MSG_DEF(MSG_SW_SCRIPT_THREW, 2, JSEXN_TYPEERR, "ServiceWorker script at {0} for scope {1} threw an exception during script evaluation.") MSG_DEF(MSG_TYPEDARRAY_IS_SHARED, 1, JSEXN_TYPEERR, "{0} can't be a typed array on SharedArrayBuffer") MSG_DEF(MSG_CACHE_ADD_FAILED_RESPONSE, 3, JSEXN_TYPEERR, "Cache got {0} response with bad status {1} while trying to add request {2}") -MSG_DEF(MSG_SW_UPDATE_BAD_REGISTRATION, 2, JSEXN_TYPEERR, "Failed to update the ServiceWorker for scope {0] because the registration has been {1} since the update was scheduled.") +MSG_DEF(MSG_SW_UPDATE_BAD_REGISTRATION, 2, JSEXN_TYPEERR, "Failed to update the ServiceWorker for scope {0} because the registration has been {1} since the update was scheduled.") MSG_DEF(MSG_INVALID_DURATION_ERROR, 1, JSEXN_TYPEERR, "Invalid duration '{0}'.") MSG_DEF(MSG_INVALID_EASING_ERROR, 1, JSEXN_TYPEERR, "Invalid easing '{0}'.") MSG_DEF(MSG_INVALID_SPACING_MODE_ERROR, 1, JSEXN_TYPEERR, "Invalid spacing '{0}'.") diff --git a/js/src/Makefile.in b/js/src/Makefile.in index fc37686501db..054c2e99489d 100644 --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -88,6 +88,9 @@ check-style:: check-masm:: (cd $(srcdir) && $(PYTHON) $(topsrcdir)/config/check_macroassembler_style.py); +check-js-msg:: + (cd $(topsrcdir) && $(PYTHON) $(topsrcdir)/config/check_js_msg_encoding.py); + check-jit-test:: $(JITTEST_SANITIZER_ENV) $(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/jit-test/jit_test.py \ --no-slow --no-progress --format=automation --jitflags=all \ @@ -95,7 +98,7 @@ check-jit-test:: $(JITTEST_EXTRA_ARGS) \ $(DIST)/bin/$(JS_SHELL_NAME)$(BIN_SUFFIX) $(JITTEST_TEST_ARGS) -check:: check-style check-masm +check:: check-style check-masm check-js-msg check-jstests: $(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/tests/jstests.py \ diff --git a/testing/mach_commands.py b/testing/mach_commands.py index 26ee9531dee9..0612d111b33b 100644 --- a/testing/mach_commands.py +++ b/testing/mach_commands.py @@ -471,7 +471,11 @@ class CheckSpiderMonkeyCommand(MachCommandBase): check_masm_cmd = [sys.executable, os.path.join(self.topsrcdir, 'config', 'check_macroassembler_style.py')] check_masm_result = subprocess.call(check_masm_cmd, cwd=os.path.join(self.topsrcdir, 'js', 'src')) - all_passed = jittest_result and jstest_result and jsapi_tests_result and check_style_result and check_masm_result + print('running check-js-msg-encoding') + check_js_msg_cmd = [sys.executable, os.path.join(self.topsrcdir, 'config', 'check_js_msg_encoding.py')] + check_js_msg_result = subprocess.call(check_js_msg_cmd, cwd=self.topsrcdir) + + all_passed = jittest_result and jstest_result and jsapi_tests_result and check_style_result and check_masm_result and check_js_msg_result return all_passed From 70a2171f15ead58e566c1e6193f956e1b430581e Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Wed, 28 Sep 2016 14:12:54 +0900 Subject: [PATCH 101/102] Bug 1300133 - Fix js-ctypes test harness to print assertion failure message and stack properly. r=bholley --- .../tests/chrome/xpcshellTestHarnessAdaptor.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/toolkit/components/ctypes/tests/chrome/xpcshellTestHarnessAdaptor.js b/toolkit/components/ctypes/tests/chrome/xpcshellTestHarnessAdaptor.js index ba11e0d5147a..eec85025b5c5 100644 --- a/toolkit/components/ctypes/tests/chrome/xpcshellTestHarnessAdaptor.js +++ b/toolkit/components/ctypes/tests/chrome/xpcshellTestHarnessAdaptor.js @@ -18,17 +18,31 @@ var Components = { }; function do_throw(message, stack) { + do_print("error: " + message); + do_print("stack: " + (stack ? stack : new Error().stack)); throw message; } function do_check_neq(left, right, stack) { - if (left == right) + if (left == right) { + var text = "do_check_neq failed"; + try { + text += ": " + left + " == " + right; + } catch (e) { + } do_throw(text, stack); + } } function do_check_eq(left, right, stack) { - if (left != right) + if (left != right) { + var text = "do_check_eq failed"; + try { + text += ": " + left + " != " + right; + } catch (e) { + } do_throw(text, stack); + } } function do_check_true(condition, stack) { From 398815ad9b0efc62eef01215b05c498c5562817b Mon Sep 17 00:00:00 2001 From: Phil Ringnalda Date: Tue, 27 Sep 2016 22:39:00 -0700 Subject: [PATCH 102/102] Backed out changeset 490c671f8047 (bug 1303121) for failures in test_CrossSiteXHR.html --- dom/base/test/test_bug435425.html | 22 +++---- dom/xhr/XMLHttpRequestMainThread.cpp | 7 ++- ...progress-events-response-data-gzip.htm.ini | 5 ++ .../tests/XMLHttpRequest/abort-after-send.htm | 39 +++++++----- .../XMLHttpRequest/abort-during-upload.htm | 2 +- .../XMLHttpRequest/abort-event-order.htm | 2 +- .../XMLHttpRequest/event-timeout-order.htm | 2 +- .../progress-events-response-data-gzip.htm | 28 ++++----- .../resources/xmlhttprequest-event-order.js | 59 ++----------------- .../send-response-event-order.htm | 37 ++++++++++-- 10 files changed, 96 insertions(+), 107 deletions(-) create mode 100644 testing/web-platform/meta/XMLHttpRequest/progress-events-response-data-gzip.htm.ini diff --git a/dom/base/test/test_bug435425.html b/dom/base/test/test_bug435425.html index 828931d67d17..0e4e3a4ebd28 100644 --- a/dom/base/test/test_bug435425.html +++ b/dom/base/test/test_bug435425.html @@ -217,7 +217,7 @@ var tests = {target: XHR, type: "loadend", optional: false}]}, { method: "GET", withUpload: none, testAbort: true, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, - {target: XHR, type: "progress", optional: true}, + {target: XHR, type: "progress", optional: false}, {target: XHR, type: "abort", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "GET", withUpload: none, testAbort: false, testRedirectError: true, testNetworkError: false, @@ -236,7 +236,7 @@ var tests = {target: XHR, type: "loadend", optional: false}]}, { method: "GET", withUpload: small, testAbort: true, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, - {target: XHR, type: "progress", optional: true}, + {target: XHR, type: "progress", optional: false}, {target: XHR, type: "abort", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "GET", withUpload: small, testAbort: false, testRedirectError: true, testNetworkError: false, @@ -255,7 +255,7 @@ var tests = {target: XHR, type: "loadend", optional: false}]}, { method: "GET", withUpload: mid, testAbort: true, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, - {target: XHR, type: "progress", optional: true}, + {target: XHR, type: "progress", optional: false}, {target: XHR, type: "abort", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "GET", withUpload: mid, testAbort: false, testRedirectError: true, testNetworkError: false, @@ -274,7 +274,7 @@ var tests = {target: XHR, type: "loadend", optional: false}]}, { method: "GET", withUpload: large, testAbort: true, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, - {target: XHR, type: "progress", optional: true}, + {target: XHR, type: "progress", optional: false}, {target: XHR, type: "abort", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "GET", withUpload: large, testAbort: false, testRedirectError: true, testNetworkError: false, @@ -293,7 +293,7 @@ var tests = {target: XHR, type: "loadend", optional: false}]}, { method: "POST", withUpload: none, testAbort: true, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, - {target: XHR, type: "progress", optional: true}, + {target: XHR, type: "progress", optional: false}, {target: XHR, type: "abort", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "POST", withUpload: none, testAbort: false, testRedirectError: true, testNetworkError: false, @@ -317,10 +317,10 @@ var tests = { method: "POST", withUpload: small, testAbort: true, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, {target: UPLOAD, type: "loadstart", optional: false}, - {target: UPLOAD, type: "progress", optional: true}, + {target: UPLOAD, type: "progress", optional: false}, {target: UPLOAD, type: "abort", optional: false}, {target: UPLOAD, type: "loadend", optional: false}, - {target: XHR, type: "progress", optional: true}, + {target: XHR, type: "progress", optional: false}, {target: XHR, type: "abort", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "POST", withUpload: small, testAbort: false, testRedirectError: true, testNetworkError: false, @@ -351,10 +351,10 @@ var tests = { method: "POST", withUpload: mid, testAbort: true, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, {target: UPLOAD, type: "loadstart", optional: false}, - {target: UPLOAD, type: "progress", optional: true}, + {target: UPLOAD, type: "progress", optional: false}, {target: UPLOAD, type: "abort", optional: false}, {target: UPLOAD, type: "loadend", optional: false}, - {target: XHR, type: "progress", optional: true}, + {target: XHR, type: "progress", optional: false}, {target: XHR, type: "abort", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "POST", withUpload: mid, testAbort: false, testRedirectError: true, testNetworkError: false, @@ -385,10 +385,10 @@ var tests = { method: "POST", withUpload: large, testAbort: true, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, {target: UPLOAD, type: "loadstart", optional: false}, - {target: UPLOAD, type: "progress", optional: true}, + {target: UPLOAD, type: "progress", optional: false}, {target: UPLOAD, type: "abort", optional: false}, {target: UPLOAD, type: "loadend", optional: false}, - {target: XHR, type: "progress", optional: true}, + {target: XHR, type: "progress", optional: false}, {target: XHR, type: "abort", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "POST", withUpload: large, testAbort: false, testRedirectError: true, testNetworkError: false, diff --git a/dom/xhr/XMLHttpRequestMainThread.cpp b/dom/xhr/XMLHttpRequestMainThread.cpp index 99162070b899..496ee55c0937 100644 --- a/dom/xhr/XMLHttpRequestMainThread.cpp +++ b/dom/xhr/XMLHttpRequestMainThread.cpp @@ -1038,8 +1038,10 @@ XMLHttpRequestMainThread::CloseRequestWithError(const ProgressEventType aType) if (!mFlagSyncLooping) { if (mUpload && !mUploadComplete) { mUploadComplete = true; + DispatchProgressEvent(mUpload, ProgressEventType::progress, 0, 0); DispatchProgressEvent(mUpload, aType, 0, 0); } + DispatchProgressEvent(this, ProgressEventType::progress, 0, 0); DispatchProgressEvent(this, aType, 0, 0); } } @@ -2182,9 +2184,10 @@ XMLHttpRequestMainThread::ChangeStateToDone() // Per spec, fire readystatechange=4/done before final error events. ChangeState(State::done, true); - // Per spec, if we failed in the upload phase, fire a final error - // and loadend events for the upload after readystatechange=4/done. + // Per spec, if we failed in the upload phase, fire a final progress, error, + // and loadend event for the upload after readystatechange=4/done. if (!mFlagSynchronous && mUpload && !mUploadComplete) { + DispatchProgressEvent(mUpload, ProgressEventType::progress, 0, 0); DispatchProgressEvent(mUpload, ProgressEventType::error, 0, 0); } diff --git a/testing/web-platform/meta/XMLHttpRequest/progress-events-response-data-gzip.htm.ini b/testing/web-platform/meta/XMLHttpRequest/progress-events-response-data-gzip.htm.ini new file mode 100644 index 000000000000..5adf572e37d3 --- /dev/null +++ b/testing/web-platform/meta/XMLHttpRequest/progress-events-response-data-gzip.htm.ini @@ -0,0 +1,5 @@ +[progress-events-response-data-gzip.htm] + type: testharness + [XMLHttpRequest: progress events and GZIP encoding] + expected: FAIL + diff --git a/testing/web-platform/tests/XMLHttpRequest/abort-after-send.htm b/testing/web-platform/tests/XMLHttpRequest/abort-after-send.htm index 523a0d616b64..c4885c9911b0 100644 --- a/testing/web-platform/tests/XMLHttpRequest/abort-after-send.htm +++ b/testing/web-platform/tests/XMLHttpRequest/abort-after-send.htm @@ -4,7 +4,6 @@ XMLHttpRequest: abort() after send() - @@ -20,26 +19,36 @@ var test = async_test() test.step(function() { var client = new XMLHttpRequest(), - control_flag = false; - prepare_xhr_for_event_order_test(client); - client.addEventListener("readystatechange", test.step_func(function() { - if(client.readyState == 4) { - control_flag = true - assert_equals(client.responseXML, null) - assert_equals(client.responseText, "") - assert_equals(client.status, 0) - assert_equals(client.statusText, "") - assert_equals(client.getAllResponseHeaders(), "") - assert_equals(client.getResponseHeader('Content-Type'), null) - } - })) + control_flag = false, + result = [], + expected = [1, 4, 'progress', 'abort', 'loadend'] // open() -> 1, abort() -> 4 + client.onreadystatechange = function() { + test.step(function() { + result.push(client.readyState) + if(client.readyState == 4) { + control_flag = true + assert_equals(client.responseXML, null) + assert_equals(client.responseText, "") + assert_equals(client.status, 0) + assert_equals(client.statusText, "") + assert_equals(client.getAllResponseHeaders(), "") + assert_equals(client.getResponseHeader('Content-Type'), null) + } + }) + } client.open("GET", "resources/well-formed.xml", true) client.send(null) + client.addEventListener('progress', logEvt) + client.addEventListener('abort', logEvt) + client.addEventListener('loadend', logEvt) client.abort() assert_true(control_flag) assert_equals(client.readyState, 0) - assert_xhr_event_order_matches([1, "loadstart(0,0,false)", 4, "abort(0,0,false)", "loadend(0,0,false)"]) + assert_array_equals(result, expected) test.done() + function logEvt (e) { + result.push(e.type) + } }) diff --git a/testing/web-platform/tests/XMLHttpRequest/abort-during-upload.htm b/testing/web-platform/tests/XMLHttpRequest/abort-during-upload.htm index 9fbc8b9bbb47..766dcc4693d8 100644 --- a/testing/web-platform/tests/XMLHttpRequest/abort-during-upload.htm +++ b/testing/web-platform/tests/XMLHttpRequest/abort-during-upload.htm @@ -18,7 +18,7 @@ client.open("POST", "resources/delay.py?ms=1000") client.addEventListener("loadend", function(e) { test.step(function() { - assert_xhr_event_order_matches([1, "loadstart(0,0,false)", "upload.loadstart(0,9999,true)", 4, "upload.abort(0,0,false)", "upload.loadend(0,0,false)", "abort(0,0,false)", "loadend(0,0,false)"]); + assert_xhr_event_order_matches([1, "loadstart(0,0,false)", "upload.loadstart(0,9999,true)", 4, "upload.progress(0,0,false)", "upload.abort(0,0,false)", "upload.loadend(0,0,false)", "progress(0,0,false)", "abort(0,0,false)", "loadend(0,0,false)"]); test.done() }) }); diff --git a/testing/web-platform/tests/XMLHttpRequest/abort-event-order.htm b/testing/web-platform/tests/XMLHttpRequest/abort-event-order.htm index f05c20628c4a..cb405a71accf 100644 --- a/testing/web-platform/tests/XMLHttpRequest/abort-event-order.htm +++ b/testing/web-platform/tests/XMLHttpRequest/abort-event-order.htm @@ -37,7 +37,7 @@ { test.step(function() { - assert_xhr_event_order_matches([1, "loadstart(0,0,false)", 4, "upload.abort(0,0,false)", "upload.loadend(0,0,false)", "abort(0,0,false)", "loadend(0,0,false)"]); + assert_xhr_event_order_matches([1, "loadstart(0,0,false)", 4, "upload.progress(0,0,false)", "upload.abort(0,0,false)", "upload.loadend(0,0,false)", "progress(0,0,false)", "abort(0,0,false)", "loadend(0,0,false)"]); assert_equals(xhr.readyState, 0, 'state should be UNSENT'); test.done(); diff --git a/testing/web-platform/tests/XMLHttpRequest/event-timeout-order.htm b/testing/web-platform/tests/XMLHttpRequest/event-timeout-order.htm index 7376ca2f8b14..1d9ba31d6e06 100644 --- a/testing/web-platform/tests/XMLHttpRequest/event-timeout-order.htm +++ b/testing/web-platform/tests/XMLHttpRequest/event-timeout-order.htm @@ -20,7 +20,7 @@ prepare_xhr_for_event_order_test(xhr); xhr.addEventListener("loadend", function() { test.step(function() { - assert_xhr_event_order_matches([1, "loadstart(0,0,false)", "upload.loadstart(0,12,true)", 4, "upload.timeout(0,0,false)", "upload.loadend(0,0,false)", "timeout(0,0,false)", "loadend(0,0,false)"]); + assert_xhr_event_order_matches([1, "loadstart(0,0,false)", "upload.loadstart(0,12,true)", 4, "upload.progress(0,0,false)", "upload.timeout(0,0,false)", "upload.loadend(0,0,false)", "progress(0,0,false)", "timeout(0,0,false)", "loadend(0,0,false)"]); test.done(); }); }); diff --git a/testing/web-platform/tests/XMLHttpRequest/progress-events-response-data-gzip.htm b/testing/web-platform/tests/XMLHttpRequest/progress-events-response-data-gzip.htm index 058064636d43..dc166a2396a4 100644 --- a/testing/web-platform/tests/XMLHttpRequest/progress-events-response-data-gzip.htm +++ b/testing/web-platform/tests/XMLHttpRequest/progress-events-response-data-gzip.htm @@ -36,20 +36,17 @@ * If lengthComputable is true: * Event.total must match Content-length header - * event.loaded must only ever increase in progress events - (and may never repeat its value). - * event.loaded must never exceed the Content-length. + * event.loaded should be a smaller number while resource is loading + and match Content-length when loading is finished + * Setting event.loaded to equal event.total for each progress event if the + resource is not fully downloaded would be cheating * If lengthComputable is false: * event.total should be 0 - * event.loaded must only ever increase in progress events - (and may never repeat its value). * event.loaded should be the length of the decompressed content, i.e. bigger than Content-length header value when finished loading */ - var lastTotal; - var lastLoaded = -1; client.addEventListener('loadend', test.step_func(function(e){ var len = parseInt(client.getResponseHeader('content-length'), 10) if(e.lengthComputable){ @@ -62,17 +59,14 @@ test.done(); }), false) client.addEventListener('progress', test.step_func(function(e){ - if(lastTotal === undefined){ - lastTotal = e.total; + if(e.lengthComputable && e.total && e.loaded && e.target.readyState < 4){ + assert_not_equals(e.total, e.loaded, 'total should not equal loaded while download/decode is incomplete') + // We should only do this assertation once + // it's theoretically possible that all the data would get in + // and a progress event fire before the readyState switches from 3 to 4 - + // in this case we might report bogus and random failures. Better to remove the event listener again.. + client.removeEventListener('progress', arguments.callee, false); } - if(e.lengthComputable && e.total && e.loaded){ - assert_equals(e.total, lastTotal, 'event.total should remain invariant') - assert_less_than_equal(e.loaded, lastTotal, 'event.loaded should not exceed content-length') - }else{ - assert_equals(e.total, 0, 'event.total should be 0') - } - assert_greater_than(e.loaded, lastLoaded, 'event.loaded should only ever increase') - lastLoaded = e.loaded; }), false) // image.gif is 165375 bytes compressed. Sending 45000 bytes at a time with 1 second delay will load it in 4 seconds client.open("GET", "resources/image.gif?pipe=gzip|trickle(45000:d1:r2)", true) diff --git a/testing/web-platform/tests/XMLHttpRequest/resources/xmlhttprequest-event-order.js b/testing/web-platform/tests/XMLHttpRequest/resources/xmlhttprequest-event-order.js index 77fc0e784ef9..820f9ee22143 100644 --- a/testing/web-platform/tests/XMLHttpRequest/resources/xmlhttprequest-event-order.js +++ b/testing/web-platform/tests/XMLHttpRequest/resources/xmlhttprequest-event-order.js @@ -21,60 +21,13 @@ } } - function getNextEvent(arr) { - var eventStr = arr.shift(); - - // we can only handle strings, numbers (readystates) and undefined - if (eventStr === undefined) { - return event; - } - if (typeof eventStr !== "string") { - if (Number.isInteger(eventStr)) { - eventStr = "readystatechange(" + eventStr + ")"; - } else { - throw "Test error: unexpected event type " + eventStr; - } - } - - // parse out the general type, loaded and total values - var type = eventStr.type = eventStr.split("(")[0].split(".").pop(); - eventStr.mayFollowOptionalProgressEvents = type == "progress" || - type == "load" || type == "abort" || type == "error"; - var loadedAndTotal = eventStr.match(/\((\d)+,(\d)+/); - if (loadedAndTotal) { - eventStr.loaded = parseInt(loadedAndTotal[0]); - eventStr.total = parseInt(loadedAndTotal[1]); - } - - return eventStr; - } - global.assert_xhr_event_order_matches = function(expected) { - var recorded = recorded_xhr_events; - var lastRecordedLoaded = -1; - - while(expected.length && recorded.length) { - var currentExpected = getNextEvent(expected), - currentRecorded = getNextEvent(recorded); - - // skip to the last progress event if we've hit one - while (recorded.length && currentRecorded.type == "progress") { - assert_greater(currentRecorded.loaded, lastRecordedLoaded, - "progress event 'loaded' values must only increase"); - lastRecordedLoaded = currentRecorded.loaded; - currentRecorded = getNextEvent(recorded); - } - if (currentRecorded.type == "loadstart") { - lastRecordedLoaded = -1; - } - - assert_equals(currentRecorded, currentExpected); - } - if (recorded.length) { - throw "\nUnexpected extra events: " + recorded.join(", "); - } - if (expected.length) { - throw "\nExpected more events: " + expected.join(", "); + try { + assert_array_equals(recorded_xhr_events, expected); + } catch(e) { + e.message += "\nRecorded events were:" + recorded_xhr_events.join(", "); + e.message += "\nExpected events were:" + expected.join(", "); + throw e; } } }(this)); diff --git a/testing/web-platform/tests/XMLHttpRequest/send-response-event-order.htm b/testing/web-platform/tests/XMLHttpRequest/send-response-event-order.htm index 041cb23c6ea8..64dfaa670f82 100644 --- a/testing/web-platform/tests/XMLHttpRequest/send-response-event-order.htm +++ b/testing/web-platform/tests/XMLHttpRequest/send-response-event-order.htm @@ -12,7 +12,6 @@ - XMLHttpRequest: The send() method: event order when synchronous flag is unset @@ -25,12 +24,38 @@ test.step(function() { var xhr = new XMLHttpRequest(); - prepare_xhr_for_event_order_test(xhr); + var expect = ["loadstart", "upload.loadstart", "upload.progress", "upload.load", "upload.loadend", "progress", 4, "load", "loadend"]; + var actual = []; - xhr.addEventListener("loadend", test.step_func(function() { - assert_xhr_event_order_matches([1, "loadstart(0,0,false)", "upload.loadstart(0,12,true)", "upload.progress(12,12,true)", "upload.load(12,12,true)", "upload.loadend(12,12,true)", 2, 3, "progress(12,12,true)", 4, "load(12,12,true)", "loadend(12,12,true)"]); - test.done(); - })); + xhr.onreadystatechange = function() + { + test.step(function() + { + if (xhr.readyState == 4) + { + actual.push(xhr.readyState); + } + }); + }; + + xhr.onloadstart = function(e){ actual.push(e.type); }; + xhr.onload = function(e){ actual.push(e.type); }; + xhr.onloadend = function(e){ actual.push(e.type); VerifyResult()}; + xhr.onprogress = function(e){ actual.push(e.type);}; + + xhr.upload.onloadstart = function(e){ actual.push("upload." + e.type); }; + xhr.upload.onload = function(e){ actual.push("upload." + e.type); }; + xhr.upload.onloadend = function(e){ actual.push("upload." + e.type);}; + xhr.upload.onprogress = function(e){ actual.push("upload." + e.type);}; + + function VerifyResult() + { + test.step(function() + { + assert_array_equals(actual, expect); + test.done(); + }); + }; xhr.open("POST", "./resources/content.py", true); xhr.send("Test Message");