From 31cf95e1cd43a81e7873d381b420ccec97209a05 Mon Sep 17 00:00:00 2001 From: Gian-Carlo Pascutto Date: Tue, 6 Oct 2015 13:53:07 +0200 Subject: [PATCH 001/228] Bug 1175562 - Persist last update time for SafeBrowsing. r=francois --- toolkit/components/build/nsToolkitCompsCID.h | 4 +- .../components/url-classifier/Classifier.cpp | 9 +++ .../components/url-classifier/Classifier.h | 1 + .../url-classifier/SafeBrowsing.jsm | 2 +- .../url-classifier/content/listmanager.js | 72 ++++++++++++++++++- .../nsIUrlClassifierDBService.idl | 9 ++- .../url-classifier/nsIUrlListManager.idl | 4 +- .../nsUrlClassifierDBService.cpp | 21 ++++++ .../url-classifier/nsUrlClassifierProxies.cpp | 15 ++++ .../url-classifier/nsUrlClassifierProxies.h | 18 +++++ 10 files changed, 148 insertions(+), 7 deletions(-) diff --git a/toolkit/components/build/nsToolkitCompsCID.h b/toolkit/components/build/nsToolkitCompsCID.h index 34742c791655..57b0da26db08 100644 --- a/toolkit/components/build/nsToolkitCompsCID.h +++ b/toolkit/components/build/nsToolkitCompsCID.h @@ -140,9 +140,9 @@ #define NS_URLCLASSIFIERPREFIXSET_CID \ { 0x3d8579f0, 0x75fa, 0x4e00, { 0xba, 0x41, 0x38, 0x66, 0x1d, 0x5b, 0x5d, 0x17} } -// {8a389f21-f821-4e29-9c6b-3de6f33cd7cf} +// {7a258022-6765-11e5-b379-b37b1f2354be} #define NS_URLCLASSIFIERDBSERVICE_CID \ -{ 0x8a389f21, 0xf821, 0x4e29, { 0x9c, 0x6b, 0x3d, 0xe6, 0xf3, 0x3c, 0xd7, 0xcf} } +{ 0x7a258022, 0x6765, 0x11e5, { 0xb3, 0x79, 0xb3, 0x7b, 0x1f, 0x23, 0x54, 0xbe} } // e1797597-f4d6-4dd3-a1e1-745ad352cd80 #define NS_URLCLASSIFIERSTREAMUPDATER_CID \ diff --git a/toolkit/components/url-classifier/Classifier.cpp b/toolkit/components/url-classifier/Classifier.cpp index eb37345621cf..43ed71a4b61e 100644 --- a/toolkit/components/url-classifier/Classifier.cpp +++ b/toolkit/components/url-classifier/Classifier.cpp @@ -368,6 +368,15 @@ Classifier::MarkSpoiled(nsTArray& aTables) return NS_OK; } +void +Classifier::SetLastUpdateTime(const nsACString &aTable, + uint64_t updateTime) +{ + LOG(("Marking table %s as last updated on %u", + PromiseFlatCString(aTable).get(), updateTime)); + mTableFreshness.Put(aTable, updateTime / PR_MSEC_PER_SEC); +} + void Classifier::DropStores() { diff --git a/toolkit/components/url-classifier/Classifier.h b/toolkit/components/url-classifier/Classifier.h index 5ec5970b5091..5587371998f8 100644 --- a/toolkit/components/url-classifier/Classifier.h +++ b/toolkit/components/url-classifier/Classifier.h @@ -60,6 +60,7 @@ public: * unnecessarily */ nsresult MarkSpoiled(nsTArray& aTables); + void SetLastUpdateTime(const nsACString& aTableName, uint64_t updateTime); nsresult CacheCompletions(const CacheResultArray& aResults); uint32_t GetHashKey(void) { return mHashKey; } /* diff --git a/toolkit/components/url-classifier/SafeBrowsing.jsm b/toolkit/components/url-classifier/SafeBrowsing.jsm index feef58c251eb..61057c2a0216 100644 --- a/toolkit/components/url-classifier/SafeBrowsing.jsm +++ b/toolkit/components/url-classifier/SafeBrowsing.jsm @@ -80,7 +80,7 @@ this.SafeBrowsing = { let providerName = this.listToProvider[listname]; let provider = this.providers[providerName]; - listManager.registerTable(listname, provider.updateURL, provider.gethashURL); + listManager.registerTable(listname, providerName, provider.updateURL, provider.gethashURL); }, registerTables: function() { diff --git a/toolkit/components/url-classifier/content/listmanager.js b/toolkit/components/url-classifier/content/listmanager.js index 2f6cd15177c8..dd56040c1f53 100644 --- a/toolkit/components/url-classifier/content/listmanager.js +++ b/toolkit/components/url-classifier/content/listmanager.js @@ -93,6 +93,7 @@ PROT_ListManager.prototype.shutdown_ = function() { * @returns true if the table could be created; false otherwise */ PROT_ListManager.prototype.registerTable = function(tableName, + providerName, updateUrl, gethashUrl) { log("registering " + tableName + " with " + updateUrl); @@ -103,6 +104,7 @@ PROT_ListManager.prototype.registerTable = function(tableName, this.tablesData[tableName] = {}; this.tablesData[tableName].updateUrl = updateUrl; this.tablesData[tableName].gethashUrl = gethashUrl; + this.tablesData[tableName].provider = providerName; // Keep track of all of our update URLs. if (!this.needsUpdate_[updateUrl]) { @@ -196,6 +198,8 @@ PROT_ListManager.prototype.kickoffUpdate_ = function (onDiskTableData) { this.startingUpdate_ = false; var initialUpdateDelay = 3000; + // Add a fuzz of 0-5 minutes. + initialUpdateDelay += Math.floor(Math.random() * (5 * 60 * 1000)); // If the user has never downloaded tables, do the check now. log("needsUpdate: " + JSON.stringify(this.needsUpdate_, undefined, 2)); @@ -206,10 +210,46 @@ PROT_ListManager.prototype.kickoffUpdate_ = function (onDiskTableData) // Don't set the updateChecker unless at least one table has updates // enabled. if (this.updatesNeeded_(updateUrl) && !this.updateCheckers_[updateUrl]) { - log("Initializing update checker for " + updateUrl); + let provider = null; + Object.keys(this.tablesData).forEach(function(table) { + if (this.tablesData[table].updateUrl === updateUrl) { + let newProvider = this.tablesData[table].provider; + if (provider) { + if (newProvider !== provider) { + log("Multiple tables for the same updateURL have a different provider?!"); + } + } else { + provider = newProvider; + } + } + }, this); + log("Initializing update checker for " + updateUrl + + " provided by " + provider); + + // Use the initialUpdateDelay + fuzz unless we had previous updates + // and the server told us when to try again. + let updateDelay = initialUpdateDelay; + let targetPref = "browser.safebrowsing.provider." + provider + ".nextupdatetime"; + let nextUpdate = this.prefs_.getPref(targetPref); + if (nextUpdate) { + updateDelay = Math.max(0, nextUpdate - Date.now()); + log("Next update at " + nextUpdate + + " which is " + updateDelay + "ms from now"); + } + + // Set the last update time to verify if data is still valid. + let freshnessPref = "browser.safebrowsing.provider." + provider + ".lastupdatetime"; + let freshness = this.prefs_.getPref(freshnessPref); + if (freshness) { + Object.keys(this.tablesData).forEach(function(table) { + if (this.tablesData[table].provider === provider) { + this.dbService_.setLastUpdateTime(table, freshness); + }}, this); + } + this.updateCheckers_[updateUrl] = new G_Alarm(BindToObject(this.checkForUpdates, this, updateUrl), - initialUpdateDelay, false /* repeating */); + updateDelay, false /* repeating */); } else { log("No updates needed or already initialized for " + updateUrl); } @@ -407,6 +447,34 @@ PROT_ListManager.prototype.updateSuccess_ = function(tableList, updateUrl, // Let the backoff object know that we completed successfully. this.requestBackoffs_[updateUrl].noteServerResponse(200); + + // Set last update time for provider + // Get the provider for these tables, check for consistency + let tables = tableList.split(","); + let provider = null; + for (let table of tables) { + let newProvider = this.tablesData[table].provider; + if (provider) { + if (newProvider !== provider) { + log("Multiple tables for the same updateURL have a different provider?!"); + } + } else { + provider = newProvider; + } + } + + // Store the last update time (needed to know if the table is "fresh") + // and the next update time (to know when to update next). + let lastUpdatePref = "browser.safebrowsing.provider." + provider + ".lastupdatetime"; + let now = Date.now(); + log("Setting last update of " + provider + " to " + now); + this.prefs_.setPref(lastUpdatePref, now.toString()); + + let nextUpdatePref = "browser.safebrowsing.provider." + provider + ".nextupdatetime"; + let targetTime = now + delay; + log("Setting next update of " + provider + " to " + targetTime + + " (" + delay + "ms from now)"); + this.prefs_.setPref(nextUpdatePref, targetTime.toString()); } /** diff --git a/toolkit/components/url-classifier/nsIUrlClassifierDBService.idl b/toolkit/components/url-classifier/nsIUrlClassifierDBService.idl index efe508e7bd6e..2cb7a084cfd8 100644 --- a/toolkit/components/url-classifier/nsIUrlClassifierDBService.idl +++ b/toolkit/components/url-classifier/nsIUrlClassifierDBService.idl @@ -66,7 +66,7 @@ interface nsIUrlClassifierUpdateObserver : nsISupports { * It provides async methods for querying and updating the database. As the * methods complete, they call the callback function. */ -[scriptable, uuid(3f9e61e5-01bd-45d0-8dd2-f1abcd20dbb7)] +[scriptable, uuid(7a258022-6765-11e5-b379-b37b1f2354be)] interface nsIUrlClassifierDBService : nsISupports { /** @@ -100,6 +100,13 @@ interface nsIUrlClassifierDBService : nsISupports void setHashCompleter(in ACString tableName, in nsIUrlClassifierHashCompleter completer); + /** + * Set the last update time for the given table. We use this to + * remember freshness past restarts. Time is in milliseconds since epoch. + */ + void setLastUpdateTime(in ACString tableName, + in unsigned long long lastUpdateTime); + //////////////////////////////////////////////////////////////////////////// // Incremental update methods. // diff --git a/toolkit/components/url-classifier/nsIUrlListManager.idl b/toolkit/components/url-classifier/nsIUrlListManager.idl index 3c5beb6a24ef..112c567dcd57 100644 --- a/toolkit/components/url-classifier/nsIUrlListManager.idl +++ b/toolkit/components/url-classifier/nsIUrlListManager.idl @@ -18,7 +18,7 @@ interface nsIUrlListManagerCallback : nsISupports { }; -[scriptable, uuid(5d5ed98f-72cd-46b6-a9fe-76418adfdfeb)] +[scriptable, uuid(d60a08ee-5c83-4eb6-bdfb-79fd0716501e)] interface nsIUrlListManager : nsISupports { /** @@ -32,10 +32,12 @@ interface nsIUrlListManager : nsISupports * @param tableName A string of the format * provider_name-semantic_type-table_type. For example, * goog-white-enchash or goog-black-url. + * @param providerName The name of the entity providing the list. * @param updateUrl The URL from which to fetch updates. * @param gethashUrl The URL from which to fetch hash completions. */ boolean registerTable(in ACString tableName, + in ACString providerName, in ACString updateUrl, in ACString gethashUrl); diff --git a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp index 0577f4022832..7789a88c1da4 100644 --- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp +++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp @@ -735,6 +735,18 @@ nsUrlClassifierDBServiceWorker::OpenDb() return NS_OK; } +nsresult +nsUrlClassifierDBServiceWorker::SetLastUpdateTime(const nsACString &table, + uint64_t updateTime) +{ + MOZ_ASSERT(!NS_IsMainThread(), "Must be on the background thread"); + MOZ_ASSERT(mClassifier, "Classifier connection must be opened"); + + mClassifier->SetLastUpdateTime(table, updateTime); + + return NS_OK; +} + // ------------------------------------------------------------------------- // nsUrlClassifierLookupCallback // @@ -1408,6 +1420,15 @@ nsUrlClassifierDBService::SetHashCompleter(const nsACString &tableName, return NS_OK; } +NS_IMETHODIMP +nsUrlClassifierDBService::SetLastUpdateTime(const nsACString &tableName, + uint64_t lastUpdateTime) +{ + NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED); + + return mWorkerProxy->SetLastUpdateTime(tableName, lastUpdateTime); +} + NS_IMETHODIMP nsUrlClassifierDBService::BeginUpdate(nsIUrlClassifierUpdateObserver *observer, const nsACString &updateTables) diff --git a/toolkit/components/url-classifier/nsUrlClassifierProxies.cpp b/toolkit/components/url-classifier/nsUrlClassifierProxies.cpp index 9c34eb5c6c47..73330d66daa0 100644 --- a/toolkit/components/url-classifier/nsUrlClassifierProxies.cpp +++ b/toolkit/components/url-classifier/nsUrlClassifierProxies.cpp @@ -216,6 +216,21 @@ UrlClassifierDBServiceWorkerProxy::CacheMissesRunnable::Run() return NS_OK; } +NS_IMETHODIMP +UrlClassifierDBServiceWorkerProxy::SetLastUpdateTime(const nsACString& table, + uint64_t lastUpdateTime) +{ + nsCOMPtr r = + new SetLastUpdateTimeRunnable(mTarget, table, lastUpdateTime); + return DispatchToWorkerThread(r); +} + +NS_IMETHODIMP +UrlClassifierDBServiceWorkerProxy::SetLastUpdateTimeRunnable::Run() +{ + mTarget->SetLastUpdateTime(mTable, mUpdateTime); + return NS_OK; +} NS_IMPL_ISUPPORTS(UrlClassifierLookupCallbackProxy, nsIUrlClassifierLookupCallback) diff --git a/toolkit/components/url-classifier/nsUrlClassifierProxies.h b/toolkit/components/url-classifier/nsUrlClassifierProxies.h index 583d2401e60d..5edd356691ce 100644 --- a/toolkit/components/url-classifier/nsUrlClassifierProxies.h +++ b/toolkit/components/url-classifier/nsUrlClassifierProxies.h @@ -173,6 +173,24 @@ public: mozilla::safebrowsing::LookupResultArray* mResults; }; + class SetLastUpdateTimeRunnable : public nsRunnable + { + public: + SetLastUpdateTimeRunnable(nsUrlClassifierDBServiceWorker* aTarget, + const nsACString& table, + uint64_t updateTime) + : mTarget(aTarget), + mTable(table), + mUpdateTime(updateTime) + { } + + NS_DECL_NSIRUNNABLE + private: + nsRefPtr mTarget; + nsCString mTable; + uint64_t mUpdateTime; + }; + public: nsresult DoLocalLookup(const nsACString& spec, const nsACString& tables, From 44f95f432cd5adabf385af5e9df881a304d430f1 Mon Sep 17 00:00:00 2001 From: Robert Longson Date: Tue, 6 Oct 2015 13:19:03 +0100 Subject: [PATCH 002/228] Bug 1204061 - check return values from some methods r=dholbert --- dom/svg/SVGPathSegListSMILType.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/dom/svg/SVGPathSegListSMILType.cpp b/dom/svg/SVGPathSegListSMILType.cpp index 2898b5b8ab48..407fdf591c0b 100644 --- a/dom/svg/SVGPathSegListSMILType.cpp +++ b/dom/svg/SVGPathSegListSMILType.cpp @@ -233,7 +233,7 @@ AddWeightedPathSegs(double aCoeff1, * identity, in which case we'll grow it to the right * size. Also allowed to be the same list as aList1. */ -static void +static nsresult AddWeightedPathSegLists(double aCoeff1, const SVGPathDataAndInfo& aList1, double aCoeff2, const SVGPathDataAndInfo& aList2, SVGPathDataAndInfo& aResult) @@ -264,8 +264,9 @@ AddWeightedPathSegLists(double aCoeff1, const SVGPathDataAndInfo& aList1, // because in that case, we will have already set iter1 to nullptr above, to // record that our first operand is an identity value.) if (aResult.IsIdentity()) { - DebugOnly success = aResult.SetLength(aList2.Length()); - MOZ_ASSERT(success, "infallible nsTArray::SetLength should succeed"); + if (!aResult.SetLength(aList2.Length())) { + return NS_ERROR_OUT_OF_MEMORY; + } aResult.SetElement(aList2.Element()); // propagate target element info! } @@ -281,6 +282,7 @@ AddWeightedPathSegLists(double aCoeff1, const SVGPathDataAndInfo& aList1, iter2 == end2 && resultIter == aResult.end(), "Very, very bad - path data corrupt"); + return NS_OK; } static void @@ -430,9 +432,7 @@ SVGPathSegListSMILType::Add(nsSMILValue& aDest, } } - AddWeightedPathSegLists(1.0, dest, aCount, valueToAdd, dest); - - return NS_OK; + return AddWeightedPathSegLists(1.0, dest, aCount, valueToAdd, dest); } nsresult @@ -483,8 +483,9 @@ SVGPathSegListSMILType::Interpolate(const nsSMILValue& aStartVal, if (check == eRequiresConversion) { // Can't convert |start| in-place, since it's const. Instead, we copy it // into |result|, converting the types as we go, and use that as our start. - DebugOnly success = result.SetLength(end.Length()); - MOZ_ASSERT(success, "infallible nsTArray::SetLength should succeed"); + if (!result.SetLength(end.Length())) { + return NS_ERROR_OUT_OF_MEMORY; + } result.SetElement(end.Element()); // propagate target element info! ConvertAllPathSegmentData(start.begin(), start.end(), @@ -493,10 +494,8 @@ SVGPathSegListSMILType::Interpolate(const nsSMILValue& aStartVal, startListToUse = &result; } - AddWeightedPathSegLists(1.0 - aUnitDistance, *startListToUse, - aUnitDistance, end, result); - - return NS_OK; + return AddWeightedPathSegLists(1.0 - aUnitDistance, *startListToUse, + aUnitDistance, end, result); } } // namespace mozilla From 8760ec0272e0a35b84d5477e013927d00199223a Mon Sep 17 00:00:00 2001 From: Neil Deakin Date: Tue, 6 Oct 2015 09:14:49 -0400 Subject: [PATCH 003/228] Bug 1206559, forward PuppetWidget::SetFocus request to the parent process, r=smaug --- dom/base/nsGlobalWindow.cpp | 8 +++----- layout/forms/test/mochitest.ini | 2 +- widget/PuppetWidget.cpp | 6 ++++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 10fa61fb2e7b..eefbee76a4b3 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -7252,13 +7252,11 @@ nsGlobalWindow::FocusOuter(ErrorResult& aError) } return; } - if (nsCOMPtr child = do_GetInterface(mDocShell)) { - child->SendRequestFocus(canFocus); - return; - } + if (canFocus) { // if there is no parent, this must be a toplevel window, so raise the - // window if canFocus is true + // window if canFocus is true. If this is a child process, the raise + // window request will get forwarded to the parent by the puppet widget. aError = fm->SetActiveWindow(this); } } diff --git a/layout/forms/test/mochitest.ini b/layout/forms/test/mochitest.ini index 7b0558b3e74c..24feb0ef6324 100644 --- a/layout/forms/test/mochitest.ini +++ b/layout/forms/test/mochitest.ini @@ -32,7 +32,7 @@ skip-if = (toolkit == 'gonk' && debug) #debug-only failure [test_bug562447.html] [test_bug563642.html] [test_bug564115.html] -skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || toolkit == 'android' || e10s #TIMED_OUT # b2g-debug(times out on window.open and focus event) b2g-desktop(times out on window.open and focus event) +skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || toolkit == 'android' #TIMED_OUT # b2g-debug(times out on window.open and focus event) b2g-desktop(times out on window.open and focus event) [test_bug571352.html] skip-if = (os == 'mac' && os_version == '10.10') || buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT # OS X 10.10 - bug 947690, b2g(shift-click multi-select not working?) b2g-debug(shift-click multi-select not working?) b2g-desktop(shift-click multi-select not working?) [test_bug572406.html] diff --git a/widget/PuppetWidget.cpp b/widget/PuppetWidget.cpp index 3236b2a74a6a..221d10de3334 100644 --- a/widget/PuppetWidget.cpp +++ b/widget/PuppetWidget.cpp @@ -257,8 +257,10 @@ PuppetWidget::ConfigureChildren(const nsTArray& aConfigurations) NS_IMETHODIMP PuppetWidget::SetFocus(bool aRaise) { - // XXX/cjones: someone who knows about event handling needs to - // decide how this should work. + if (aRaise && mTabChild) { + mTabChild->SendRequestFocus(true); + } + return NS_OK; } From db947f012d322219908fab1cda7ee5f09901e568 Mon Sep 17 00:00:00 2001 From: John Dai Date: Thu, 24 Sep 2015 07:35:00 +0200 Subject: [PATCH 004/228] Bug 1207548 - Add ssltunnel in xulrunner.zip. r=wcosta --HG-- extra : rebase_source : 97c0f1794a85cc5510575274c7b6e8798905521a --- testing/taskcluster/tasks/tests/b2g_build_test.yml | 2 +- testing/taskcluster/tasks/tests/b2g_emulator_mochitest.yml | 3 ++- .../taskcluster/tasks/tests/b2g_emulator_mochitest_media.yml | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/testing/taskcluster/tasks/tests/b2g_build_test.yml b/testing/taskcluster/tasks/tests/b2g_build_test.yml index 5862175a799c..f829daa9c59c 100644 --- a/testing/taskcluster/tasks/tests/b2g_build_test.yml +++ b/testing/taskcluster/tasks/tests/b2g_build_test.yml @@ -22,7 +22,7 @@ task: --download-symbols ondemand --gaia-repo https://hg.mozilla.org/integration/gaia-central --gaia-dir /home/worker - --xre-url https://queue.taskcluster.net/v1/task/wXAHAaxDQpqxoWF1iljJjg/runs/0/artifacts/public/cache/xulrunner-sdk-40.zip + --xre-url http://people.mozilla.org/~jdai/xulrunner-sdk-40.zip artifacts: 'public/build': type: directory diff --git a/testing/taskcluster/tasks/tests/b2g_emulator_mochitest.yml b/testing/taskcluster/tasks/tests/b2g_emulator_mochitest.yml index a5850f56d285..b38b4dd77ff7 100644 --- a/testing/taskcluster/tasks/tests/b2g_emulator_mochitest.yml +++ b/testing/taskcluster/tasks/tests/b2g_emulator_mochitest.yml @@ -13,6 +13,7 @@ task: - entrypoint - > python ./mozharness/scripts/b2g_emulator_unittest.py + --no-read-buildbot-config --config-file ./mozharness/configs/b2g/emulator_automation_config.py --config-file ./mozharness_configs/gaia_integration_override.py --config-file ./mozharness_configs/emulator_override.py @@ -21,7 +22,7 @@ task: --test-suite mochitest --installer-url {{build_url}} --test-packages-url {{test_packages_url}} - --xre-url https://queue.taskcluster.net/v1/task/wXAHAaxDQpqxoWF1iljJjg/runs/0/artifacts/public/cache/xulrunner-sdk-40.zip + --xre-url http://people.mozilla.org/~jdai/xulrunner-sdk-40.zip --this-chunk {{chunk}} --total-chunk {{total_chunks}} artifacts: diff --git a/testing/taskcluster/tasks/tests/b2g_emulator_mochitest_media.yml b/testing/taskcluster/tasks/tests/b2g_emulator_mochitest_media.yml index 50fd012d834f..773677b13b8f 100644 --- a/testing/taskcluster/tasks/tests/b2g_emulator_mochitest_media.yml +++ b/testing/taskcluster/tasks/tests/b2g_emulator_mochitest_media.yml @@ -12,6 +12,7 @@ task: - entrypoint - > python ./mozharness/scripts/b2g_emulator_unittest.py + --no-read-buildbot-config --config-file ./mozharness/configs/b2g/emulator_automation_config.py --config-file ./mozharness_configs/gaia_integration_override.py --config-file ./mozharness_configs/emulator_override.py @@ -20,7 +21,7 @@ task: --test-suite mochitest --installer-url {{build_url}} --test-packages-url {{test_packages_url}} - --xre-url https://queue.taskcluster.net/v1/task/wXAHAaxDQpqxoWF1iljJjg/runs/0/artifacts/public/cache/xulrunner-sdk-40.zip + --xre-url http://people.mozilla.org/~jdai/xulrunner-sdk-40.zip dom/media/tests artifacts: 'public/build': From 43f3f27e22bf20ddf464555a5520ea981b676289 Mon Sep 17 00:00:00 2001 From: John Dai Date: Mon, 5 Oct 2015 22:57:00 +0200 Subject: [PATCH 005/228] Bug 1204800 - Add tooltool dependencies to phone builds. r=wcosta --HG-- extra : rebase_source : ea7bfcf753e7ca371b248b56961dabffb4f0bdd3 --- .../aries-dogfood/releng-aries-dogfood.tt | 16 ++++++++++ .../aries-spark-ota/releng-aries-spark-ota.tt | 16 ++++++++++ b2g/config/aries/config.json | 2 +- b2g/config/aries/releng-aries.tt | 16 +++++----- b2g/config/dolphin-512/releng-dolphin-512.tt | 16 ++++++++++ b2g/config/dolphin/releng-dolphin.tt | 9 +++++- .../flame-kk-ota/releng-flame-kk-ota.tt | 16 ++++++++++ b2g/config/flame-kk/config.json | 2 +- b2g/config/flame-kk/releng-flame-kk.tt | 16 +++++----- b2g/config/flame/config.json | 2 +- b2g/config/flame/releng-flame.tt | 14 +++++---- b2g/config/nexus-4-kk/releng-mako.tt | 28 +++++------------ b2g/config/nexus-4/releng-mako.tt | 30 ++++++------------- b2g/config/nexus-5-l/releng-nexus5.tt | 12 ++++++-- .../scripts/phone-builder/pre-build.sh | 3 ++ .../tasks/builds/b2g_aries_spark_debug.yml | 1 + .../tasks/builds/b2g_aries_spark_dogfood.yml | 1 + .../tasks/builds/b2g_aries_spark_eng.yml | 1 + .../tasks/builds/b2g_aries_spark_opt.yml | 1 + .../builds/b2g_aries_spark_ota_debug.yml | 1 + .../tasks/builds/b2g_aries_spark_ota_opt.yml | 2 +- .../tasks/builds/b2g_dolphin_512_eng.yml | 2 +- .../tasks/builds/b2g_dolphin_512_opt.yml | 1 + .../tasks/builds/b2g_dolphin_eng.yml | 1 + .../tasks/builds/b2g_dolphin_opt.yml | 2 +- .../tasks/builds/b2g_flame_kk_debug.yml | 1 + .../tasks/builds/b2g_flame_kk_eng.yml | 1 + .../tasks/builds/b2g_flame_kk_opt.yml | 1 + .../tasks/builds/b2g_flame_kk_ota_debug.yml | 1 + .../tasks/builds/b2g_flame_kk_ota_opt.yml | 1 + .../tasks/builds/b2g_flame_kk_spark_eng.yml | 1 + .../tasks/builds/b2g_nexus_4_eng.yml | 1 + .../tasks/builds/b2g_nexus_4_kk_eng.yml | 1 + .../tasks/builds/b2g_nexus_4_kk_user.yml | 1 + .../tasks/builds/b2g_nexus_4_user.yml | 1 + .../tasks/builds/b2g_nexus_5l_eng.yml | 1 + .../tasks/builds/b2g_nexus_5l_user.yml | 1 + .../tasks/builds/b2g_phone_base.yml | 4 +++ testing/taskcluster/tasks/phone_build.yml | 2 ++ 39 files changed, 157 insertions(+), 72 deletions(-) create mode 100644 b2g/config/aries-dogfood/releng-aries-dogfood.tt create mode 100644 b2g/config/aries-spark-ota/releng-aries-spark-ota.tt create mode 100644 b2g/config/dolphin-512/releng-dolphin-512.tt create mode 100644 b2g/config/flame-kk-ota/releng-flame-kk-ota.tt diff --git a/b2g/config/aries-dogfood/releng-aries-dogfood.tt b/b2g/config/aries-dogfood/releng-aries-dogfood.tt new file mode 100644 index 000000000000..4f97e6b2db87 --- /dev/null +++ b/b2g/config/aries-dogfood/releng-aries-dogfood.tt @@ -0,0 +1,16 @@ +[ +{ +"size": 80458572, +"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad", +"algorithm": "sha512", +"filename": "gcc.tar.xz", +"unpack": true +}, +{ +"size": 12057960, +"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e", +"algorithm": "sha512", +"filename": "gtk3.tar.xz", +"unpack": true +} +] diff --git a/b2g/config/aries-spark-ota/releng-aries-spark-ota.tt b/b2g/config/aries-spark-ota/releng-aries-spark-ota.tt new file mode 100644 index 000000000000..4f97e6b2db87 --- /dev/null +++ b/b2g/config/aries-spark-ota/releng-aries-spark-ota.tt @@ -0,0 +1,16 @@ +[ +{ +"size": 80458572, +"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad", +"algorithm": "sha512", +"filename": "gcc.tar.xz", +"unpack": true +}, +{ +"size": 12057960, +"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e", +"algorithm": "sha512", +"filename": "gtk3.tar.xz", +"unpack": true +} +] diff --git a/b2g/config/aries/config.json b/b2g/config/aries/config.json index 93683c532cfe..a5f97937bb48 100644 --- a/b2g/config/aries/config.json +++ b/b2g/config/aries/config.json @@ -39,7 +39,7 @@ }, "b2g_manifest": "aries.xml", "b2g_manifest_intree": true, - "additional_source_tarballs": ["backup-aries.tar.xz"], + "additional_source_tarballs": [], "gecko_l10n_root": "https://hg.mozilla.org/l10n-central", "gaia": { "l10n": { diff --git a/b2g/config/aries/releng-aries.tt b/b2g/config/aries/releng-aries.tt index 74b32b01f17b..4f97e6b2db87 100644 --- a/b2g/config/aries/releng-aries.tt +++ b/b2g/config/aries/releng-aries.tt @@ -1,16 +1,16 @@ [ { -"size": 135359412, -"digest": "45e677c9606cc4eec44ef4761df47ff431df1ffad17a5c6d21ce700a1c47f79e87a4aa9f30ae47ff060bd64f5b775d995780d88211f9a759ffa0d076beb4816b", -"algorithm": "sha512", -"filename": "backup-aries.tar.xz", -"comment": "v18D" -}, -{ "size": 80458572, "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad", "algorithm": "sha512", "filename": "gcc.tar.xz", -"unpack": "True" +"unpack": true +}, +{ +"size": 12057960, +"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e", +"algorithm": "sha512", +"filename": "gtk3.tar.xz", +"unpack": true } ] diff --git a/b2g/config/dolphin-512/releng-dolphin-512.tt b/b2g/config/dolphin-512/releng-dolphin-512.tt new file mode 100644 index 000000000000..4f97e6b2db87 --- /dev/null +++ b/b2g/config/dolphin-512/releng-dolphin-512.tt @@ -0,0 +1,16 @@ +[ +{ +"size": 80458572, +"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad", +"algorithm": "sha512", +"filename": "gcc.tar.xz", +"unpack": true +}, +{ +"size": 12057960, +"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e", +"algorithm": "sha512", +"filename": "gtk3.tar.xz", +"unpack": true +} +] diff --git a/b2g/config/dolphin/releng-dolphin.tt b/b2g/config/dolphin/releng-dolphin.tt index 1af12208b9da..4f97e6b2db87 100644 --- a/b2g/config/dolphin/releng-dolphin.tt +++ b/b2g/config/dolphin/releng-dolphin.tt @@ -4,6 +4,13 @@ "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad", "algorithm": "sha512", "filename": "gcc.tar.xz", -"unpack": "True" +"unpack": true +}, +{ +"size": 12057960, +"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e", +"algorithm": "sha512", +"filename": "gtk3.tar.xz", +"unpack": true } ] diff --git a/b2g/config/flame-kk-ota/releng-flame-kk-ota.tt b/b2g/config/flame-kk-ota/releng-flame-kk-ota.tt new file mode 100644 index 000000000000..4f97e6b2db87 --- /dev/null +++ b/b2g/config/flame-kk-ota/releng-flame-kk-ota.tt @@ -0,0 +1,16 @@ +[ +{ +"size": 80458572, +"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad", +"algorithm": "sha512", +"filename": "gcc.tar.xz", +"unpack": true +}, +{ +"size": 12057960, +"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e", +"algorithm": "sha512", +"filename": "gtk3.tar.xz", +"unpack": true +} +] diff --git a/b2g/config/flame-kk/config.json b/b2g/config/flame-kk/config.json index 15cfa1a584db..271945e1f0e3 100644 --- a/b2g/config/flame-kk/config.json +++ b/b2g/config/flame-kk/config.json @@ -41,7 +41,7 @@ }, "b2g_manifest": "flame-kk.xml", "b2g_manifest_intree": true, - "additional_source_tarballs": ["backup-flame.tar.xz"], + "additional_source_tarballs": [], "gecko_l10n_root": "https://hg.mozilla.org/l10n-central", "gaia": { "l10n": { diff --git a/b2g/config/flame-kk/releng-flame-kk.tt b/b2g/config/flame-kk/releng-flame-kk.tt index d0e0c584aa85..4f97e6b2db87 100644 --- a/b2g/config/flame-kk/releng-flame-kk.tt +++ b/b2g/config/flame-kk/releng-flame-kk.tt @@ -1,16 +1,16 @@ [ { -"size": 135359412, -"digest": "45e677c9606cc4eec44ef4761df47ff431df1ffad17a5c6d21ce700a1c47f79e87a4aa9f30ae47ff060bd64f5b775d995780d88211f9a759ffa0d076beb4816b", -"algorithm": "sha512", -"filename": "backup-flame.tar.xz", -"comment": "v18D" -}, -{ "size": 80458572, "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad", "algorithm": "sha512", "filename": "gcc.tar.xz", -"unpack": "True" +"unpack": true +}, +{ +"size": 12057960, +"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e", +"algorithm": "sha512", +"filename": "gtk3.tar.xz", +"unpack": true } ] diff --git a/b2g/config/flame/config.json b/b2g/config/flame/config.json index 6757312a0834..71515cd32c93 100644 --- a/b2g/config/flame/config.json +++ b/b2g/config/flame/config.json @@ -40,7 +40,7 @@ }, "b2g_manifest": "flame.xml", "b2g_manifest_intree": true, - "additional_source_tarballs": ["backup-flame.tar.xz"], + "additional_source_tarballs": [], "gecko_l10n_root": "https://hg.mozilla.org/l10n-central", "gaia": { "l10n": { diff --git a/b2g/config/flame/releng-flame.tt b/b2g/config/flame/releng-flame.tt index 65f9871b6796..4f97e6b2db87 100644 --- a/b2g/config/flame/releng-flame.tt +++ b/b2g/config/flame/releng-flame.tt @@ -1,14 +1,16 @@ [ -{"size": 149922032, -"digest": "8d1a71552ffee561e93b5b3f1bb47866592ab958f908007c75561156430eb1b85a265bfc4dc2038e58dda0264daa9854877a84ef3b591c9ac2f1ab97c098e61e", -"filename": "backup-flame.tar.xz", -"algorithm": "sha512" -}, { "size": 80458572, "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad", "algorithm": "sha512", "filename": "gcc.tar.xz", -"unpack": "True" +"unpack": true +}, +{ +"size": 12057960, +"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e", +"algorithm": "sha512", +"filename": "gtk3.tar.xz", +"unpack": true } ] diff --git a/b2g/config/nexus-4-kk/releng-mako.tt b/b2g/config/nexus-4-kk/releng-mako.tt index bd916f022cb3..35a9d3a879ed 100644 --- a/b2g/config/nexus-4-kk/releng-mako.tt +++ b/b2g/config/nexus-4-kk/releng-mako.tt @@ -1,28 +1,16 @@ -[ -{ -"size": i13096, -"digest": "674475286c1639379079dca3cd14bfb9cc2a7e23733cd0f96e20296b2ee6dc0cdb9fccdc8635bef0475add156e085c17b946ec2c4254c83d3bef95d027e03537", -"algorithm": "sha512", -"filename": "broadcom-mako-kot49h-18b58457.tgz" -}, -{ -"size": 17661109, -"digest": "a5fcd2fda9fec1d24bb15e160f0ac2627a2b65e411f737c6cac48e777847c5a9eef3251af7deb535af89643a05e9889b857d1f60bf11df18fa270fd7b2db16db", -"algorithm": "sha512", -"filename": "qcom-mako-kot49h-e7a74920.tgz" -}, -{ -"size": 163277, -"digest": "e58aad76e6395a1a82fe886783842c4676c12d065e2f65bce6ce19cab2488be767aaea27fa2f46f48a0bf8d9714a6b453b474d2f9df5de158c49e6cbde0a359e", -"algorithm": "sha512", -"filename": "lge-mako-kot49h-f59c98be.tgz" -}, -{ +[{ "size": 80458572, "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad", "algorithm": "sha512", "filename": "gcc.tar.xz", "unpack": "True" +}, +{ +"size": 12057960, +"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e", +"algorithm": "sha512", +"filename": "gtk3.tar.xz", +"unpack": true } ] diff --git a/b2g/config/nexus-4/releng-mako.tt b/b2g/config/nexus-4/releng-mako.tt index f83b6888fd46..608c2521e92c 100644 --- a/b2g/config/nexus-4/releng-mako.tt +++ b/b2g/config/nexus-4/releng-mako.tt @@ -1,28 +1,16 @@ [ { -"size": 13111, -"digest": "09373556ddb4325897b9e008184228f9088b4c8c22bacf4fa2d39793ecfd264316ad69c2bc8082229ad7fdb80f89154c7b995a60f9b18beb1847e7111e7e69b2", -"algorithm": "sha512", -"filename": "broadcom-mako-jwr66v-cbde0d61.tgz" -}, -{ -"size": 12658359, -"digest": "2483df1a949df53d02ca33a87731cedd8f7cd07114d723bde1addf63fd71154c23b6f11f64f390b9849121725fb53a402db8df2f96a3673ec52416f45260f79d", -"algorithm": "sha512", -"filename": "qcom-mako-jwr66v-30ef957c.tgz" -}, -{ -"size": 378532, -"digest": "27aced8feb0e757d61df37839e62410ff30a059cfa8f04897d29ab74b787c765313acf904b1f9cf311c3e682883514df7da54197665251ef9b8bdad6bd0f62c5", -"algorithm": "sha512", -"filename": "lge-mako-jwr66v-985845e4.tgz" -}, -{ "size": 80458572, "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad", "algorithm": "sha512", "filename": "gcc.tar.xz", -"unpack": "True" +"unpack": true +}, +{ +"size": 12057960, +"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e", +"algorithm": "sha512", +"filename": "gtk3.tar.xz", +"unpack": true } -] - +] \ No newline at end of file diff --git a/b2g/config/nexus-5-l/releng-nexus5.tt b/b2g/config/nexus-5-l/releng-nexus5.tt index c29e812bbb41..5e02a2162c22 100644 --- a/b2g/config/nexus-5-l/releng-nexus5.tt +++ b/b2g/config/nexus-5-l/releng-nexus5.tt @@ -3,5 +3,13 @@ "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad", "algorithm": "sha512", "filename": "gcc.tar.xz", -"unpack": "True" -}] +"unpack": true +}, +{ +"size": 12057960, +"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e", +"algorithm": "sha512", +"filename": "gtk3.tar.xz", +"unpack": true +} +] diff --git a/testing/taskcluster/scripts/phone-builder/pre-build.sh b/testing/taskcluster/scripts/phone-builder/pre-build.sh index 000e7ef444b6..ac44b1ce2d09 100755 --- a/testing/taskcluster/scripts/phone-builder/pre-build.sh +++ b/testing/taskcluster/scripts/phone-builder/pre-build.sh @@ -26,6 +26,9 @@ tc-vcs repo-checkout $WORKSPACE/B2G https://git.mozilla.org/b2g/B2G.git $MANIFES rm -f $WORKSPACE/B2G/gecko ln -s $WORKSPACE/gecko $WORKSPACE/B2G/gecko +### Install package dependencies +. ../builder/install-packages.sh $WORKSPACE/gecko + debug_flag="" if [ 0$B2G_DEBUG -ne 0 ]; then debug_flag='--debug' diff --git a/testing/taskcluster/tasks/builds/b2g_aries_spark_debug.yml b/testing/taskcluster/tasks/builds/b2g_aries_spark_debug.yml index 0c751a811aa1..b3e946cc5fc7 100644 --- a/testing/taskcluster/tasks/builds/b2g_aries_spark_debug.yml +++ b/testing/taskcluster/tasks/builds/b2g_aries_spark_debug.yml @@ -22,6 +22,7 @@ task: GAIA_OPTIMIZE: '1' B2G_SYSTEM_APPS: '1' MOZHARNESS_CONFIG: b2g/taskcluster-spark.py + TOOLTOOL_MANIFEST: 'b2g/config/aries/releng-aries.tt' command: - > checkout-gecko workspace && diff --git a/testing/taskcluster/tasks/builds/b2g_aries_spark_dogfood.yml b/testing/taskcluster/tasks/builds/b2g_aries_spark_dogfood.yml index 99a859487897..5e8ef782be65 100644 --- a/testing/taskcluster/tasks/builds/b2g_aries_spark_dogfood.yml +++ b/testing/taskcluster/tasks/builds/b2g_aries_spark_dogfood.yml @@ -18,6 +18,7 @@ task: DOGFOOD: 1 HARDWARE_COMPOSER: 0 MOZHARNESS_CONFIG: b2g/taskcluster-spark-dogfood.py + TOOLTOOL_MANIFEST: 'b2g/config/aries-dogfood/releng-aries-dogfood.tt' extra: treeherderEnv: - production diff --git a/testing/taskcluster/tasks/builds/b2g_aries_spark_eng.yml b/testing/taskcluster/tasks/builds/b2g_aries_spark_eng.yml index 7c3e71fc05c4..f138a3475740 100644 --- a/testing/taskcluster/tasks/builds/b2g_aries_spark_eng.yml +++ b/testing/taskcluster/tasks/builds/b2g_aries_spark_eng.yml @@ -17,6 +17,7 @@ task: env: TARGET: 'aries' MOZHARNESS_CONFIG: b2g/taskcluster-spark.py + TOOLTOOL_MANIFEST: 'b2g/config/aries/releng-aries.tt' extra: treeherderEnv: - production diff --git a/testing/taskcluster/tasks/builds/b2g_aries_spark_opt.yml b/testing/taskcluster/tasks/builds/b2g_aries_spark_opt.yml index 9207c05a7e62..c2aa962fa5c5 100644 --- a/testing/taskcluster/tasks/builds/b2g_aries_spark_opt.yml +++ b/testing/taskcluster/tasks/builds/b2g_aries_spark_opt.yml @@ -22,6 +22,7 @@ task: GAIA_OPTIMIZE: '1' B2G_SYSTEM_APPS: '1' MOZHARNESS_CONFIG: b2g/taskcluster-spark.py + TOOLTOOL_MANIFEST: 'b2g/config/aries/releng-aries.tt' command: - > checkout-gecko workspace && diff --git a/testing/taskcluster/tasks/builds/b2g_aries_spark_ota_debug.yml b/testing/taskcluster/tasks/builds/b2g_aries_spark_ota_debug.yml index a62627ad4e63..d83ce13af5b2 100644 --- a/testing/taskcluster/tasks/builds/b2g_aries_spark_ota_debug.yml +++ b/testing/taskcluster/tasks/builds/b2g_aries_spark_ota_debug.yml @@ -16,4 +16,5 @@ task: env: VARIANT: userdebug B2G_DEBUG: 0 + TOOLTOOL_MANIFEST: 'b2g/config/aries-spark-ota/releng-aries-spark-ota.tt' diff --git a/testing/taskcluster/tasks/builds/b2g_aries_spark_ota_opt.yml b/testing/taskcluster/tasks/builds/b2g_aries_spark_ota_opt.yml index c7c63437386c..19c5006e1c29 100644 --- a/testing/taskcluster/tasks/builds/b2g_aries_spark_ota_opt.yml +++ b/testing/taskcluster/tasks/builds/b2g_aries_spark_ota_opt.yml @@ -15,4 +15,4 @@ task: build-aries-spark-ota-user-objdir-gecko-{{project}}: /home/worker/objdir-gecko env: VARIANT: user - + TOOLTOOL_MANIFEST: 'b2g/config/aries-spark-ota/releng-aries-spark-ota.tt' diff --git a/testing/taskcluster/tasks/builds/b2g_dolphin_512_eng.yml b/testing/taskcluster/tasks/builds/b2g_dolphin_512_eng.yml index 044de79850e6..46ff4a08dbc6 100644 --- a/testing/taskcluster/tasks/builds/b2g_dolphin_512_eng.yml +++ b/testing/taskcluster/tasks/builds/b2g_dolphin_512_eng.yml @@ -20,4 +20,4 @@ task: env: TARGET: 'dolphin-512' VARIANT: eng - + TOOLTOOL_MANIFEST: 'b2g/config/dolphin-512/releng-dolphin-512.tt' diff --git a/testing/taskcluster/tasks/builds/b2g_dolphin_512_opt.yml b/testing/taskcluster/tasks/builds/b2g_dolphin_512_opt.yml index e51e0ce2a692..e1d4489211de 100644 --- a/testing/taskcluster/tasks/builds/b2g_dolphin_512_opt.yml +++ b/testing/taskcluster/tasks/builds/b2g_dolphin_512_opt.yml @@ -18,3 +18,4 @@ task: build-dolphin-512-opt: /home/worker/workspace env: TARGET: 'dolphin-512' + TOOLTOOL_MANIFEST: 'b2g/config/dolphin-512/releng-dolphin-512.tt' \ No newline at end of file diff --git a/testing/taskcluster/tasks/builds/b2g_dolphin_eng.yml b/testing/taskcluster/tasks/builds/b2g_dolphin_eng.yml index ae1aa3c940fc..000d0e25c5e3 100644 --- a/testing/taskcluster/tasks/builds/b2g_dolphin_eng.yml +++ b/testing/taskcluster/tasks/builds/b2g_dolphin_eng.yml @@ -20,3 +20,4 @@ task: env: TARGET: 'dolphin' VARIANT: eng + TOOLTOOL_MANIFEST: 'b2g/config/dolphin/releng-dolphin.tt' \ No newline at end of file diff --git a/testing/taskcluster/tasks/builds/b2g_dolphin_opt.yml b/testing/taskcluster/tasks/builds/b2g_dolphin_opt.yml index a6a45d4892d1..ec623766182a 100644 --- a/testing/taskcluster/tasks/builds/b2g_dolphin_opt.yml +++ b/testing/taskcluster/tasks/builds/b2g_dolphin_opt.yml @@ -18,4 +18,4 @@ task: build-dolphin-opt: /home/worker/workspace env: TARGET: 'dolphin' - + TOOLTOOL_MANIFEST: 'b2g/config/dolphin/releng-dolphin.tt' diff --git a/testing/taskcluster/tasks/builds/b2g_flame_kk_debug.yml b/testing/taskcluster/tasks/builds/b2g_flame_kk_debug.yml index 42fc7744d197..61c9ce96308b 100644 --- a/testing/taskcluster/tasks/builds/b2g_flame_kk_debug.yml +++ b/testing/taskcluster/tasks/builds/b2g_flame_kk_debug.yml @@ -19,6 +19,7 @@ task: TARGET: 'flame-kk' DEBUG: 0 VARIANT: userdebug + TOOLTOOL_MANIFEST: 'b2g/config/flame-kk/releng-flame-kk.tt' command: - > checkout-gecko workspace && diff --git a/testing/taskcluster/tasks/builds/b2g_flame_kk_eng.yml b/testing/taskcluster/tasks/builds/b2g_flame_kk_eng.yml index 7d8f1cfe8cff..1b1c7452c173 100644 --- a/testing/taskcluster/tasks/builds/b2g_flame_kk_eng.yml +++ b/testing/taskcluster/tasks/builds/b2g_flame_kk_eng.yml @@ -16,6 +16,7 @@ task: build-flame-kk-eng-objdir-gecko-{{project}}: /home/worker/objdir-gecko env: TARGET: 'flame-kk' + TOOLTOOL_MANIFEST: 'b2g/config/flame-kk/releng-flame-kk.tt' extra: treeherderEnv: - production diff --git a/testing/taskcluster/tasks/builds/b2g_flame_kk_opt.yml b/testing/taskcluster/tasks/builds/b2g_flame_kk_opt.yml index e007d5bbcc63..0e06f93d1733 100644 --- a/testing/taskcluster/tasks/builds/b2g_flame_kk_opt.yml +++ b/testing/taskcluster/tasks/builds/b2g_flame_kk_opt.yml @@ -18,6 +18,7 @@ task: env: TARGET: 'flame-kk' DEBUG: 0 + TOOLTOOL_MANIFEST: 'b2g/config/flame-kk/releng-flame-kk.tt' command: - > checkout-gecko workspace && diff --git a/testing/taskcluster/tasks/builds/b2g_flame_kk_ota_debug.yml b/testing/taskcluster/tasks/builds/b2g_flame_kk_ota_debug.yml index ed19afcbe5bb..634725d39434 100644 --- a/testing/taskcluster/tasks/builds/b2g_flame_kk_ota_debug.yml +++ b/testing/taskcluster/tasks/builds/b2g_flame_kk_ota_debug.yml @@ -17,3 +17,4 @@ task: env: VARIANT: userdebug B2G_DEBUG: 0 + TOOLTOOL_MANIFEST: 'b2g/config/flame-kk-ota/releng-flame-kk-ota.tt' \ No newline at end of file diff --git a/testing/taskcluster/tasks/builds/b2g_flame_kk_ota_opt.yml b/testing/taskcluster/tasks/builds/b2g_flame_kk_ota_opt.yml index 0be3a4c569af..37fc84205341 100644 --- a/testing/taskcluster/tasks/builds/b2g_flame_kk_ota_opt.yml +++ b/testing/taskcluster/tasks/builds/b2g_flame_kk_ota_opt.yml @@ -16,3 +16,4 @@ task: build-flame-kk-ota-user-objdir-gecko-{{project}}: /home/worker/objdir-gecko env: VARIANT: user + TOOLTOOL_MANIFEST: 'b2g/config/flame-kk-ota/releng-flame-kk-ota.tt' \ No newline at end of file diff --git a/testing/taskcluster/tasks/builds/b2g_flame_kk_spark_eng.yml b/testing/taskcluster/tasks/builds/b2g_flame_kk_spark_eng.yml index 87150044afc7..4e2eeb0d878c 100644 --- a/testing/taskcluster/tasks/builds/b2g_flame_kk_spark_eng.yml +++ b/testing/taskcluster/tasks/builds/b2g_flame_kk_spark_eng.yml @@ -17,6 +17,7 @@ task: env: TARGET: 'flame-kk' MOZHARNESS_CONFIG: b2g/taskcluster-spark.py + TOOLTOOL_MANIFEST: 'b2g/config/flame-kk/releng-flame-kk.tt' extra: treeherderEnv: - staging diff --git a/testing/taskcluster/tasks/builds/b2g_nexus_4_eng.yml b/testing/taskcluster/tasks/builds/b2g_nexus_4_eng.yml index 1f725f1da679..176a36a64eb2 100644 --- a/testing/taskcluster/tasks/builds/b2g_nexus_4_eng.yml +++ b/testing/taskcluster/tasks/builds/b2g_nexus_4_eng.yml @@ -15,6 +15,7 @@ task: env: TARGET: 'nexus-4' DEBUG: 0 + TOOLTOOL_MANIFEST: 'b2g/config/nexus-4/releng-mako.tt' command: - > checkout-gecko workspace && diff --git a/testing/taskcluster/tasks/builds/b2g_nexus_4_kk_eng.yml b/testing/taskcluster/tasks/builds/b2g_nexus_4_kk_eng.yml index 4265ea6ee247..711329410a06 100644 --- a/testing/taskcluster/tasks/builds/b2g_nexus_4_kk_eng.yml +++ b/testing/taskcluster/tasks/builds/b2g_nexus_4_kk_eng.yml @@ -17,6 +17,7 @@ task: env: TARGET: 'nexus-4-kk' DEBUG: 0 + TOOLTOOL_MANIFEST: 'b2g/config/nexus-4-kk/releng-mako.tt' command: - > checkout-gecko workspace && diff --git a/testing/taskcluster/tasks/builds/b2g_nexus_4_kk_user.yml b/testing/taskcluster/tasks/builds/b2g_nexus_4_kk_user.yml index b2dbf01e98dd..1e47aaf95f0a 100644 --- a/testing/taskcluster/tasks/builds/b2g_nexus_4_kk_user.yml +++ b/testing/taskcluster/tasks/builds/b2g_nexus_4_kk_user.yml @@ -17,6 +17,7 @@ task: env: TARGET: 'nexus-4-kk' DEBUG: 0 + TOOLTOOL_MANIFEST: 'b2g/config/nexus-4-kk/releng-mako.tt' command: - > checkout-gecko workspace && diff --git a/testing/taskcluster/tasks/builds/b2g_nexus_4_user.yml b/testing/taskcluster/tasks/builds/b2g_nexus_4_user.yml index e7a8423b7555..31248eb6e4d8 100644 --- a/testing/taskcluster/tasks/builds/b2g_nexus_4_user.yml +++ b/testing/taskcluster/tasks/builds/b2g_nexus_4_user.yml @@ -16,6 +16,7 @@ task: env: TARGET: 'nexus-4' DEBUG: 0 + TOOLTOOL_MANIFEST: 'b2g/config/nexus-4/releng-mako.tt' command: - > checkout-gecko workspace && diff --git a/testing/taskcluster/tasks/builds/b2g_nexus_5l_eng.yml b/testing/taskcluster/tasks/builds/b2g_nexus_5l_eng.yml index 20591c022a3a..6ceb7a036cab 100644 --- a/testing/taskcluster/tasks/builds/b2g_nexus_5l_eng.yml +++ b/testing/taskcluster/tasks/builds/b2g_nexus_5l_eng.yml @@ -15,6 +15,7 @@ task: env: TARGET: 'nexus-5-l' DEBUG: 0 + TOOLTOOL_MANIFEST: 'b2g/config/nexus-5-l/releng-nexus5.tt' command: - > checkout-gecko workspace && diff --git a/testing/taskcluster/tasks/builds/b2g_nexus_5l_user.yml b/testing/taskcluster/tasks/builds/b2g_nexus_5l_user.yml index b6321287c4b5..01eb8832f282 100644 --- a/testing/taskcluster/tasks/builds/b2g_nexus_5l_user.yml +++ b/testing/taskcluster/tasks/builds/b2g_nexus_5l_user.yml @@ -16,6 +16,7 @@ task: env: TARGET: 'nexus-5-l' DEBUG: 0 + TOOLTOOL_MANIFEST: 'b2g/config/nexus-5-l/releng-nexus5.tt' command: - > checkout-gecko workspace && diff --git a/testing/taskcluster/tasks/builds/b2g_phone_base.yml b/testing/taskcluster/tasks/builds/b2g_phone_base.yml index 1ab2648fe3db..1e00c07e9aff 100644 --- a/testing/taskcluster/tasks/builds/b2g_phone_base.yml +++ b/testing/taskcluster/tasks/builds/b2g_phone_base.yml @@ -1,10 +1,14 @@ $inherits: from: 'tasks/phone_build.yml' task: + scopes: + - 'docker-worker:cache:tooltool-cache' metadata: description: | Android phones + b2g environment used in full stack testing. payload: + cache: + tooltool-cache: '/home/worker/tooltool-cache' env: MOZILLA_OFFICIAL: '1' ENABLE_DEFAULT_BOOTANIMATION: 'true' diff --git a/testing/taskcluster/tasks/phone_build.yml b/testing/taskcluster/tasks/phone_build.yml index 9ef39d34611c..08b9f518b7b1 100644 --- a/testing/taskcluster/tasks/phone_build.yml +++ b/testing/taskcluster/tasks/phone_build.yml @@ -54,6 +54,8 @@ task: GECKO_HEAD_REPOSITORY: '{{head_repository}}' GECKO_HEAD_REV: '{{head_rev}}' GECKO_HEAD_REF: '{{head_ref}}' + TOOLTOOL_REPO: 'https://git.mozilla.org/build/tooltool.git' + TOOLTOOL_REV: 'master' extra: build_product: 'b2g' From d080cc4a26dcf8379e32049144eb08e060bebef7 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Tue, 6 Oct 2015 06:37:06 -0700 Subject: [PATCH 006/228] Bug 1210941 P1 Create the LOAD_BYPASS_SERVICE_WORKER flag. r=jduell --- netwerk/base/nsIChannel.idl | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/netwerk/base/nsIChannel.idl b/netwerk/base/nsIChannel.idl index cc9486f77764..efd32c352578 100644 --- a/netwerk/base/nsIChannel.idl +++ b/netwerk/base/nsIChannel.idl @@ -29,7 +29,7 @@ interface nsIStreamListener; * * This interface must be used only from the XPCOM main thread. */ -[scriptable, uuid(cc3bff29-324e-4704-9eeb-1b8a62c4a9dc)] +[scriptable, uuid(2c389865-23db-4aa7-9fe5-60cc7b00697e)] interface nsIChannel : nsIRequest { /** @@ -192,7 +192,7 @@ interface nsIChannel : nsIRequest /************************************************************************** * Channel specific load flags: * - * Bits 23-31 are reserved for future use by this interface or one of its + * Bits 26-31 are reserved for future use by this interface or one of its * derivatives (e.g., see nsICachingChannel). */ @@ -272,6 +272,13 @@ interface nsIChannel : nsIRequest */ const unsigned long LOAD_EXPLICIT_CREDENTIALS = 1 << 24; + /** + * Set to force bypass of any service worker interception of the channel. + */ + const unsigned long LOAD_BYPASS_SERVICE_WORKER = 1 << 25; + + // nsICachingChannel load flags begin at bit 26. + /** * Access to the type implied or stated by the Content-Disposition header * if available and if applicable. This allows determining inline versus From 5f0bbc9218c84c55170e8e45bf9d44a10c435a95 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Tue, 6 Oct 2015 06:37:06 -0700 Subject: [PATCH 007/228] Bug 1210941 P2 Use LOAD_BYPASS_SERVICE_WORKER in HttpBaseChannel instead of mForceNoIntercept. r=jduell --- netwerk/protocol/http/HttpBaseChannel.cpp | 19 ++++++++++--------- netwerk/protocol/http/HttpBaseChannel.h | 5 ++--- netwerk/protocol/http/nsHttpChannel.cpp | 1 + 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp index b3cae7d47b5a..01feee7f8190 100644 --- a/netwerk/protocol/http/HttpBaseChannel.cpp +++ b/netwerk/protocol/http/HttpBaseChannel.cpp @@ -77,7 +77,6 @@ HttpBaseChannel::HttpBaseChannel() , mResponseTimeoutEnabled(true) , mAllRedirectsSameOrigin(true) , mAllRedirectsPassTimingAllowCheck(true) - , mForceNoIntercept(false) , mResponseCouldBeSynthesized(false) , mSuspendCount(0) , mInitialRwin(0) @@ -1572,6 +1571,8 @@ HttpBaseChannel::OverrideSecurityInfo(nsISupports* aSecurityInfo) "This can only be called when we don't have a security info object already"); MOZ_RELEASE_ASSERT(aSecurityInfo, "This can only be called with a valid security info object"); + MOZ_ASSERT(!BypassServiceWorker(), + "This can only be called on channels that are not bypassing interception"); MOZ_ASSERT(mResponseCouldBeSynthesized, "This can only be called on channels that can be intercepted"); if (mSecurityInfo) { @@ -2116,8 +2117,7 @@ HttpBaseChannel::GetLastModifiedTime(PRTime* lastModifiedTime) NS_IMETHODIMP HttpBaseChannel::ForceNoIntercept() { - mForceNoIntercept = true; - mResponseCouldBeSynthesized = false; + mLoadFlags |= LOAD_BYPASS_SERVICE_WORKER; return NS_OK; } @@ -2261,13 +2261,19 @@ HttpBaseChannel::IsNavigation() return mForceMainDocumentChannel; } +bool +HttpBaseChannel::BypassServiceWorker() const +{ + return mLoadFlags & LOAD_BYPASS_SERVICE_WORKER; +} + bool HttpBaseChannel::ShouldIntercept() { nsCOMPtr controller; GetCallback(controller); bool shouldIntercept = false; - if (controller && !mForceNoIntercept && mLoadInfo) { + if (controller && !BypassServiceWorker() && mLoadInfo) { nsContentPolicyType type = mLoadInfo->InternalContentPolicyType(); nsresult rv = controller->ShouldPrepareForIntercept(mURI, IsNavigation(), @@ -2549,11 +2555,6 @@ HttpBaseChannel::SetupReplacementChannel(nsIURI *newURI, httpInternal->SetCacheKeysRedirectChain(mRedirectedCachekeys.forget()); } - // Preserve any skip-serviceworker-flag. - if (mForceNoIntercept) { - httpInternal->ForceNoIntercept(); - } - // Preserve CORS mode flag. httpInternal->SetCorsMode(mCorsMode); diff --git a/netwerk/protocol/http/HttpBaseChannel.h b/netwerk/protocol/http/HttpBaseChannel.h index 13ddb1e4ce8e..e434bba37a95 100644 --- a/netwerk/protocol/http/HttpBaseChannel.h +++ b/netwerk/protocol/http/HttpBaseChannel.h @@ -315,6 +315,8 @@ protected: // GetPrincipal Returns the channel's URI principal. nsIPrincipal *GetURIPrincipal(); + bool BypassServiceWorker() const; + // Returns true if this channel should intercept the network request and prepare // for a possible synthesized response instead. bool ShouldIntercept(); @@ -393,9 +395,6 @@ protected: // pass the Resource Timing timing-allow-check uint32_t mAllRedirectsPassTimingAllowCheck : 1; - // True if this channel should skip any interception checks - uint32_t mForceNoIntercept : 1; - // True if this channel was intercepted and could receive a synthesized response. uint32_t mResponseCouldBeSynthesized : 1; diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index 464ddb3ae4d0..b838bc98182e 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -7021,6 +7021,7 @@ nsHttpChannel::OnPush(const nsACString &url, Http2PushedStream *pushedStream) void nsHttpChannel::SetCouldBeSynthesized() { + MOZ_ASSERT(!BypassServiceWorker()); mResponseCouldBeSynthesized = true; } From bf39f45faee8aba85d416de66f8e1d930fb1310b Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Tue, 6 Oct 2015 06:37:06 -0700 Subject: [PATCH 008/228] Bug 1210941 P3 Make jar channels use LOAD_BYPASS_SERVICE_WORKER internally. r=jduell --- modules/libjar/nsJARChannel.cpp | 11 ++++++++--- modules/libjar/nsJARChannel.h | 5 ++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/modules/libjar/nsJARChannel.cpp b/modules/libjar/nsJARChannel.cpp index a5ce7d52713b..8493b220d870 100644 --- a/modules/libjar/nsJARChannel.cpp +++ b/modules/libjar/nsJARChannel.cpp @@ -203,7 +203,6 @@ nsJARChannel::nsJARChannel() , mIsUnsafe(true) , mOpeningRemote(false) , mSynthesizedStreamLength(0) - , mForceNoIntercept(false) , mBlockRemoteFiles(false) { if (!gJarProtocolLog) @@ -863,6 +862,12 @@ nsJARChannel::Open2(nsIInputStream** aStream) return Open(aStream); } +bool +nsJARChannel::BypassServiceWorker() const +{ + return mLoadFlags & LOAD_BYPASS_SERVICE_WORKER; +} + bool nsJARChannel::ShouldIntercept() { @@ -877,7 +882,7 @@ nsJARChannel::ShouldIntercept() NS_GET_IID(nsINetworkInterceptController), getter_AddRefs(controller)); bool shouldIntercept = false; - if (controller && !mForceNoIntercept && mLoadInfo) { + if (controller && !BypassServiceWorker() && mLoadInfo) { bool isNavigation = mLoadFlags & LOAD_DOCUMENT_URI; nsContentPolicyType type = mLoadInfo->InternalContentPolicyType(); nsresult rv = controller->ShouldPrepareForIntercept(mAppURI, @@ -1124,7 +1129,7 @@ nsJARChannel::GetZipEntry(nsIZipEntry **aZipEntry) NS_IMETHODIMP nsJARChannel::ForceNoIntercept() { - mForceNoIntercept = true; + mLoadFlags |= LOAD_BYPASS_SERVICE_WORKER; return NS_OK; } diff --git a/modules/libjar/nsJARChannel.h b/modules/libjar/nsJARChannel.h index 6f205497f4d5..b8cad253afd1 100644 --- a/modules/libjar/nsJARChannel.h +++ b/modules/libjar/nsJARChannel.h @@ -80,6 +80,8 @@ private: mozilla::net::MemoryDownloader::Data aData) override; + bool BypassServiceWorker() const; + // Returns true if this channel should intercept the network request and // prepare for a possible synthesized response instead. bool ShouldIntercept(); @@ -136,9 +138,6 @@ private: nsRefPtr mSynthesizedResponsePump; int64_t mSynthesizedStreamLength; - // True if this channel should skip any interception checks. - bool mForceNoIntercept; - // True if this channel should not download any remote files. bool mBlockRemoteFiles; friend class mozilla::net::InterceptedJARChannel; From eaa946bccc2276c1d71fc338cdbc720f524bd362 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Tue, 6 Oct 2015 06:37:07 -0700 Subject: [PATCH 009/228] Bug 1210941 P4 Use LOAD_BYPASS_SERVICE_WORKER instead of ForceNoIntercept in nsDocShell. r=ehsan --- docshell/base/nsDocShell.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 7ebae42325b4..209c242ae908 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -10897,17 +10897,14 @@ nsDocShell::DoChannelLoad(nsIChannel* aChannel, loadFlags |= nsIChannel::LOAD_CLASSIFY_URI; } - (void)aChannel->SetLoadFlags(loadFlags); - // If the user pressed shift-reload, then do not allow ServiceWorker // interception to occur. See step 12.1 of the SW HandleFetch algorithm. if (IsForceReloadType(mLoadType)) { - nsCOMPtr internal = do_QueryInterface(aChannel); - if (internal) { - internal->ForceNoIntercept(); - } + loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER; } + (void)aChannel->SetLoadFlags(loadFlags); + uint32_t openFlags = 0; if (mLoadType == LOAD_LINK) { openFlags |= nsIURILoader::IS_CONTENT_PREFERRED; From 4ef3a4d97d4e78cda9fc4b784ffc25b2876ac9a6 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Tue, 6 Oct 2015 06:37:07 -0700 Subject: [PATCH 010/228] Bug 1210941 P5 Use LOAD_BYPASS_SERVICE_WORKER in nsObjectLoadingContent instead of ForceNoIntercept(). r=ehsan --- dom/base/nsObjectLoadingContent.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/dom/base/nsObjectLoadingContent.cpp b/dom/base/nsObjectLoadingContent.cpp index 3311b57e72c2..8e65e692a077 100644 --- a/dom/base/nsObjectLoadingContent.cpp +++ b/dom/base/nsObjectLoadingContent.cpp @@ -21,7 +21,6 @@ #include "nsIDOMHTMLAppletElement.h" #include "nsIExternalProtocolHandler.h" #include "nsIInterfaceRequestorUtils.h" -#include "nsIHttpChannelInternal.h" #include "nsIObjectFrame.h" #include "nsIPermissionManager.h" #include "nsPluginHost.h" @@ -2535,7 +2534,8 @@ nsObjectLoadingContent::OpenChannel() group, // aLoadGroup shim, // aCallbacks nsIChannel::LOAD_CALL_CONTENT_SNIFFERS | - nsIChannel::LOAD_CLASSIFY_URI); + nsIChannel::LOAD_CLASSIFY_URI | + nsIChannel::LOAD_BYPASS_SERVICE_WORKER); NS_ENSURE_SUCCESS(rv, rv); @@ -2558,13 +2558,6 @@ nsObjectLoadingContent::OpenChannel() scriptChannel->SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL); } - nsCOMPtr internalChannel = do_QueryInterface(httpChan); - if (internalChannel) { - // Bug 1168676. object/embed tags are not allowed to be intercepted by - // ServiceWorkers. - internalChannel->ForceNoIntercept(); - } - // AsyncOpen can fail if a file does not exist. rv = chan->AsyncOpen(shim, nullptr); NS_ENSURE_SUCCESS(rv, rv); From 5522a3ae19ea8ea03f0f54cfca3e3ac46305abb1 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Tue, 6 Oct 2015 06:37:07 -0700 Subject: [PATCH 011/228] Bug 1210941 P6 Use LOAD_BYPASS_SERVICE_WORKER instead of ForceNoIntercept in FetchDriver. r=ehsan --- dom/fetch/FetchDriver.cpp | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/dom/fetch/FetchDriver.cpp b/dom/fetch/FetchDriver.cpp index c323d42529fb..55361c0c417f 100644 --- a/dom/fetch/FetchDriver.cpp +++ b/dom/fetch/FetchDriver.cpp @@ -428,6 +428,12 @@ FetchDriver::HttpFetch(bool aCORSFlag, bool aCORSPreflightFlag, bool aAuthentica // new cookies sent by the server from being stored. const nsLoadFlags credentialsFlag = useCredentials ? 0 : nsIRequest::LOAD_ANONYMOUS; + // Set skip serviceworker flag. + // While the spec also gates on the client being a ServiceWorker, we can't + // infer that here. Instead we rely on callers to set the flag correctly. + const nsLoadFlags bypassFlag = mRequest->SkipServiceWorker() ? + nsIChannel::LOAD_BYPASS_SERVICE_WORKER : 0; + // From here on we create a channel and set its properties with the // information from the InternalRequest. This is an implementation detail. MOZ_ASSERT(mLoadGroup); @@ -439,7 +445,7 @@ FetchDriver::HttpFetch(bool aCORSFlag, bool aCORSPreflightFlag, bool aAuthentica mRequest->ContentPolicyType(), mLoadGroup, nullptr, /* aCallbacks */ - nsIRequest::LOAD_NORMAL | credentialsFlag, + nsIRequest::LOAD_NORMAL | credentialsFlag | bypassFlag, ios); mLoadGroup = nullptr; if (NS_WARN_IF(NS_FAILED(rv))) { @@ -575,21 +581,6 @@ FetchDriver::HttpFetch(bool aCORSFlag, bool aCORSPreflightFlag, bool aAuthentica } } - // Set skip serviceworker flag. - // While the spec also gates on the client being a ServiceWorker, we can't - // infer that here. Instead we rely on callers to set the flag correctly. - if (mRequest->SkipServiceWorker()) { - if (httpChan) { - nsCOMPtr internalChan = do_QueryInterface(httpChan); - internalChan->ForceNoIntercept(); - } else { - nsCOMPtr jarChannel = do_QueryInterface(chan); - // If it is not an http channel, it has to be a jar one. - MOZ_ASSERT(jarChannel); - jarChannel->ForceNoIntercept(); - } - } - nsCOMPtr listener = this; // Only use nsCORSListenerProxy if we are in CORS mode. Otherwise it From fd3893120c5a8752381be1363e896aa3d5d60df8 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Tue, 6 Oct 2015 06:37:07 -0700 Subject: [PATCH 012/228] Bug 1210941 P7 Use LOAD_BYPASS_SERVICE_WORKER in ServiceWorkerScriptCache. r=ehsan --- dom/workers/ServiceWorkerScriptCache.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/dom/workers/ServiceWorkerScriptCache.cpp b/dom/workers/ServiceWorkerScriptCache.cpp index 1c44aa1ed83b..03f91ba5beaf 100644 --- a/dom/workers/ServiceWorkerScriptCache.cpp +++ b/dom/workers/ServiceWorkerScriptCache.cpp @@ -117,7 +117,9 @@ public: uri, aPrincipal, nsILoadInfo::SEC_NORMAL, nsIContentPolicy::TYPE_INTERNAL_SCRIPT, - loadGroup); + loadGroup, + nullptr, // aCallbacks + nsIChannel::LOAD_BYPASS_SERVICE_WORKER); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -140,12 +142,6 @@ public: httpChannel->SetRedirectionLimit(0); } - // Don't let serviceworker intercept. - nsCOMPtr internalChannel = do_QueryInterface(mChannel); - if (internalChannel) { - internalChannel->ForceNoIntercept(); - } - nsCOMPtr loader; rv = NS_NewStreamLoader(getter_AddRefs(loader), this, this); if (NS_WARN_IF(NS_FAILED(rv))) { From 8f13441162f7fec188d95d4ba00a6620a6ee405e Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Tue, 6 Oct 2015 06:37:07 -0700 Subject: [PATCH 013/228] Bug 1210941 P8 Use LOAD_BYPASS_SERVICE_WORKER in xslt txURIUtils. r=ehsan --- dom/xslt/base/txURIUtils.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/dom/xslt/base/txURIUtils.cpp b/dom/xslt/base/txURIUtils.cpp index 27c94a5c18a4..33f7e919aa06 100644 --- a/dom/xslt/base/txURIUtils.cpp +++ b/dom/xslt/base/txURIUtils.cpp @@ -65,16 +65,13 @@ URIUtils::ResetWithSource(nsIDocument *aNewDoc, nsIDOMNode *aSourceNode) sourceDoc, nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL, nsIContentPolicy::TYPE_OTHER, - loadGroup); + loadGroup, + nullptr, // aCallbacks + nsIChannel::LOAD_BYPASS_SERVICE_WORKER); if (NS_FAILED(rv)) { return; } - - nsCOMPtr internalChannel = do_QueryInterface(channel); - if (internalChannel) { - internalChannel->ForceNoIntercept(); - } } aNewDoc->Reset(channel, loadGroup); From d908cf03844fca39fb17addb688cb99635433393 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Tue, 6 Oct 2015 06:37:07 -0700 Subject: [PATCH 014/228] Bug 1210941 P9 Use LOAD_BYPASS_SERVICE_WORKER in nsCORSListenerProxy. r=ehsan --- netwerk/protocol/http/nsCORSListenerProxy.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/netwerk/protocol/http/nsCORSListenerProxy.cpp b/netwerk/protocol/http/nsCORSListenerProxy.cpp index 8bf4f132d5d1..9b1a47232482 100644 --- a/netwerk/protocol/http/nsCORSListenerProxy.cpp +++ b/netwerk/protocol/http/nsCORSListenerProxy.cpp @@ -1347,6 +1347,14 @@ nsCORSListenerProxy::StartCORSPreflight(nsIChannel* aRequestChannel, rv = aRequestChannel->GetLoadFlags(&loadFlags); NS_ENSURE_SUCCESS(rv, rv); + // Preflight requests should never be intercepted by service workers. + // NOTE: We ignore CORS checks on synthesized responses (see the CORS + // preflights, then we need to extend the GetResponseSynthesized() check in + // nsCORSListenerProxy::CheckRequestApproved()). If we change our behavior + // here and allow service workers to intercept CORS preflights, then that + // check won't be safe any more. + loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER; + nsCOMPtr preflightChannel; rv = NS_NewChannelInternal(getter_AddRefs(preflightChannel), uri, @@ -1362,17 +1370,6 @@ nsCORSListenerProxy::StartCORSPreflight(nsIChannel* aRequestChannel, rv = preHttp->SetRequestMethod(NS_LITERAL_CSTRING("OPTIONS")); NS_ENSURE_SUCCESS(rv, rv); - // Preflight requests should never be intercepted by service workers. - nsCOMPtr preInternal = do_QueryInterface(preflightChannel); - if (preInternal) { - // NOTE: We ignore CORS checks on synthesized responses (see the CORS - // preflights, then we need to extend the GetResponseSynthesized() check in - // nsCORSListenerProxy::CheckRequestApproved()). If we change our behavior - // here and allow service workers to intercept CORS preflights, then that - // check won't be safe any more. - preInternal->ForceNoIntercept(); - } - // Set up listener which will start the original channel nsCOMPtr preflightListener = new nsCORSPreflightListener(aRequestChannel, aListener, nullptr, aPrincipal, From 65ad5a613b5de225a983047a56554ee207163e27 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Tue, 6 Oct 2015 06:37:07 -0700 Subject: [PATCH 015/228] Bug 1210941 P10 Use LOAD_BYPASS_SERVICE_WORKER in nsNSSCallbacks. r=ehsan --- security/manager/ssl/nsNSSCallbacks.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/security/manager/ssl/nsNSSCallbacks.cpp b/security/manager/ssl/nsNSSCallbacks.cpp index 9e05acffcea2..3e14c3985c44 100644 --- a/security/manager/ssl/nsNSSCallbacks.cpp +++ b/security/manager/ssl/nsNSSCallbacks.cpp @@ -102,7 +102,8 @@ nsHTTPDownloadEvent::Run() if (priorityChannel) priorityChannel->AdjustPriority(nsISupportsPriority::PRIORITY_HIGHEST); - chan->SetLoadFlags(nsIRequest::LOAD_ANONYMOUS); + chan->SetLoadFlags(nsIRequest::LOAD_ANONYMOUS | + nsIChannel::LOAD_BYPASS_SERVICE_WORKER); // Create a loadgroup for this new channel. This way if the channel // is redirected, we'll have a way to cancel the resulting channel. @@ -134,9 +135,6 @@ nsHTTPDownloadEvent::Run() if (internalChannel) { rv = internalChannel->SetAllowSpdy(false); NS_ENSURE_SUCCESS(rv, rv); - // OCSP requests should never be intercepted. - rv = internalChannel->ForceNoIntercept(); - NS_ENSURE_SUCCESS(rv, rv); } nsCOMPtr hchan = do_QueryInterface(chan); From 323efab6af90fdfec8ae3468051fdb9d5fc1c13d Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Tue, 6 Oct 2015 06:37:07 -0700 Subject: [PATCH 016/228] Bug 1210941 P11 Use LOAD_BYPASS_SERVICE_WORKER in worker ScriptLoader. r=ehsan --- dom/workers/ScriptLoader.cpp | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/dom/workers/ScriptLoader.cpp b/dom/workers/ScriptLoader.cpp index 5260070a1807..d51579ea114e 100644 --- a/dom/workers/ScriptLoader.cpp +++ b/dom/workers/ScriptLoader.cpp @@ -107,6 +107,7 @@ ChannelFromScriptURL(nsIPrincipal* principal, bool aIsMainScript, WorkerScriptType aWorkerScriptType, nsContentPolicyType aContentPolicyType, + nsLoadFlags aLoadFlags, nsIChannel** aChannel) { AssertIsOnMainThread(); @@ -159,7 +160,7 @@ ChannelFromScriptURL(nsIPrincipal* principal, NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_SECURITY_ERR); } - uint32_t flags = nsIRequest::LOAD_NORMAL | nsIChannel::LOAD_CLASSIFY_URI; + aLoadFlags |= nsIChannel::LOAD_CLASSIFY_URI; nsCOMPtr channel; // If we have the document, use it @@ -171,7 +172,7 @@ ChannelFromScriptURL(nsIPrincipal* principal, aContentPolicyType, loadGroup, nullptr, // aCallbacks - flags, + aLoadFlags, ios); } else { // We must have a loadGroup with a load context for the principal to @@ -186,7 +187,7 @@ ChannelFromScriptURL(nsIPrincipal* principal, aContentPolicyType, loadGroup, nullptr, // aCallbacks - flags, + aLoadFlags, ios); } @@ -849,11 +850,20 @@ private: ScriptLoadInfo& loadInfo = mLoadInfos[aIndex]; nsresult& rv = loadInfo.mLoadResult; + nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL; + + // If we are loading a script for a ServiceWorker then we must not + // try to intercept it. If the interception matches the current + // ServiceWorker's scope then we could deadlock the load. + if (mWorkerPrivate->IsServiceWorker()) { + loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER; + } + if (!channel) { rv = ChannelFromScriptURL(principal, baseURI, parentDoc, loadGroup, ios, secMan, loadInfo.mURL, IsMainWorkerScript(), mWorkerScriptType, - mWorkerPrivate->ContentPolicyType(), + mWorkerPrivate->ContentPolicyType(), loadFlags, getter_AddRefs(channel)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; @@ -881,16 +891,6 @@ private: return rv; } - // If we are loading a script for a ServiceWorker then we must not - // try to intercept it. If the interception matches the current - // ServiceWorker's scope then we could deadlock the load. - if (mWorkerPrivate->IsServiceWorker()) { - nsCOMPtr internal = do_QueryInterface(channel); - if (internal) { - internal->ForceNoIntercept(); - } - } - if (loadInfo.mCacheStatus != ScriptLoadInfo::ToBeCached) { rv = channel->AsyncOpen(loader, indexSupports); if (NS_WARN_IF(NS_FAILED(rv))) { @@ -1858,7 +1858,8 @@ ChannelFromScriptURLMainThread(nsIPrincipal* aPrincipal, return ChannelFromScriptURL(aPrincipal, aBaseURI, aParentDoc, aLoadGroup, ios, secMan, aScriptURL, true, WorkerScript, - aContentPolicyType, aChannel); + aContentPolicyType, nsIRequest::LOAD_NORMAL, + aChannel); } nsresult From 031144370f53976255e29a790b2004d8dca83cfa Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Tue, 6 Oct 2015 06:37:07 -0700 Subject: [PATCH 017/228] Bug 1210941 P12 Remove http channel's ForceNoIntercept. r=jduell IGNORE IDL --- netwerk/protocol/http/HttpBaseChannel.cpp | 7 ------- netwerk/protocol/http/HttpBaseChannel.h | 1 - netwerk/protocol/http/HttpChannelChild.cpp | 2 +- netwerk/protocol/http/HttpChannelParent.cpp | 5 ++++- netwerk/protocol/http/nsHttpChannel.cpp | 10 ++++++---- netwerk/protocol/http/nsIHttpChannelInternal.idl | 6 ------ 6 files changed, 11 insertions(+), 20 deletions(-) diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp index 01feee7f8190..64c98de26cbd 100644 --- a/netwerk/protocol/http/HttpBaseChannel.cpp +++ b/netwerk/protocol/http/HttpBaseChannel.cpp @@ -2114,13 +2114,6 @@ HttpBaseChannel::GetLastModifiedTime(PRTime* lastModifiedTime) return NS_OK; } -NS_IMETHODIMP -HttpBaseChannel::ForceNoIntercept() -{ - mLoadFlags |= LOAD_BYPASS_SERVICE_WORKER; - return NS_OK; -} - NS_IMETHODIMP HttpBaseChannel::GetCorsIncludeCredentials(bool* aInclude) { diff --git a/netwerk/protocol/http/HttpBaseChannel.h b/netwerk/protocol/http/HttpBaseChannel.h index e434bba37a95..07bba14af310 100644 --- a/netwerk/protocol/http/HttpBaseChannel.h +++ b/netwerk/protocol/http/HttpBaseChannel.h @@ -196,7 +196,6 @@ public: NS_IMETHOD SetNetworkInterfaceId(const nsACString& aNetworkInterfaceId) override; NS_IMETHOD ForcePending(bool aForcePending) override; NS_IMETHOD GetLastModifiedTime(PRTime* lastModifiedTime) override; - NS_IMETHOD ForceNoIntercept() override; NS_IMETHOD GetCorsIncludeCredentials(bool* aInclude) override; NS_IMETHOD SetCorsIncludeCredentials(bool aInclude) override; NS_IMETHOD GetCorsMode(uint32_t* aCorsMode) override; diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp index ef012331ad5c..7da331eb916a 100644 --- a/netwerk/protocol/http/HttpChannelChild.cpp +++ b/netwerk/protocol/http/HttpChannelChild.cpp @@ -2243,7 +2243,7 @@ HttpChannelChild::ResetInterception() // The chance to intercept any further requests associated with this channel // (such as redirects) has passed. - ForceNoIntercept(); + mLoadFlags |= LOAD_BYPASS_SERVICE_WORKER; // Continue with the original cross-process request nsresult rv = ContinueAsyncOpen(); diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp index 46e8aa01addb..999caf425f5d 100644 --- a/netwerk/protocol/http/HttpChannelParent.cpp +++ b/netwerk/protocol/http/HttpChannelParent.cpp @@ -503,7 +503,10 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI, } } else { - mChannel->ForceNoIntercept(); + nsLoadFlags loadFlags; + mChannel->GetLoadFlags(&loadFlags); + loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER; + mChannel->SetLoadFlags(loadFlags); } nsCOMPtr cacheKey = diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index b838bc98182e..57981e312dd8 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -2009,10 +2009,12 @@ nsHttpChannel::StartRedirectChannelToURI(nsIURI *upgradedURI, uint32_t flags) // Ensure that internally-redirected channels cannot be intercepted, which would look // like two separate requests to the nsINetworkInterceptController. - nsCOMPtr httpRedirect = do_QueryInterface(mRedirectChannel); - if (httpRedirect) { - httpRedirect->ForceNoIntercept(); - } + nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL; + rv = mRedirectChannel->GetLoadFlags(&loadFlags); + NS_ENSURE_SUCCESS(rv, rv); + loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER; + rv = mRedirectChannel->SetLoadFlags(loadFlags); + NS_ENSURE_SUCCESS(rv, rv); PushRedirectAsyncFunc( &nsHttpChannel::ContinueAsyncRedirectChannelToURI); diff --git a/netwerk/protocol/http/nsIHttpChannelInternal.idl b/netwerk/protocol/http/nsIHttpChannelInternal.idl index cb6345708d39..3bc2817ea8d2 100644 --- a/netwerk/protocol/http/nsIHttpChannelInternal.idl +++ b/netwerk/protocol/http/nsIHttpChannelInternal.idl @@ -223,12 +223,6 @@ interface nsIHttpChannelInternal : nsISupports readonly attribute PRTime lastModifiedTime; - /** - * Force a channel that has not been AsyncOpen'ed to skip any check for possible - * interception and proceed immediately to the network/cache. - */ - void forceNoIntercept(); - readonly attribute boolean responseSynthesized; /** From 0482554d13f52c09c5b31708b1639fd34cf307b6 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Tue, 6 Oct 2015 06:37:07 -0700 Subject: [PATCH 018/228] Bug 1210941 P13 Remove ForceNoIntercept from jar channel. r=jduell --- modules/libjar/nsIJARChannel.idl | 8 +------- modules/libjar/nsJARChannel.cpp | 7 ------- netwerk/protocol/app/AppProtocolHandler.cpp | 5 ----- 3 files changed, 1 insertion(+), 19 deletions(-) diff --git a/modules/libjar/nsIJARChannel.idl b/modules/libjar/nsIJARChannel.idl index 7fb6484ab407..b1ec6c722f9b 100644 --- a/modules/libjar/nsIJARChannel.idl +++ b/modules/libjar/nsIJARChannel.idl @@ -8,7 +8,7 @@ interface nsIFile; interface nsIZipEntry; -[scriptable, builtinclass, uuid(1adea16e-aa6c-4201-8f71-e9ff0acfb52e)] +[scriptable, builtinclass, uuid(e72b179b-d5df-4d87-b5de-fd73a65c60f6)] interface nsIJARChannel : nsIChannel { /** @@ -34,10 +34,4 @@ interface nsIJARChannel : nsIChannel * This will work even without opening the channel. */ readonly attribute nsIZipEntry zipEntry; - - /** - * Force the channel to skip any chack for possible interception and - * proceed immediately to the network. - */ - void forceNoIntercept(); }; diff --git a/modules/libjar/nsJARChannel.cpp b/modules/libjar/nsJARChannel.cpp index 8493b220d870..3d080302ff1c 100644 --- a/modules/libjar/nsJARChannel.cpp +++ b/modules/libjar/nsJARChannel.cpp @@ -1126,13 +1126,6 @@ nsJARChannel::GetZipEntry(nsIZipEntry **aZipEntry) return reader->GetEntry(mJarEntry, aZipEntry); } -NS_IMETHODIMP -nsJARChannel::ForceNoIntercept() -{ - mLoadFlags |= LOAD_BYPASS_SERVICE_WORKER; - return NS_OK; -} - //----------------------------------------------------------------------------- // mozilla::net::MemoryDownloader::IObserver //----------------------------------------------------------------------------- diff --git a/netwerk/protocol/app/AppProtocolHandler.cpp b/netwerk/protocol/app/AppProtocolHandler.cpp index 99fd9c6bf89a..00028b414187 100644 --- a/netwerk/protocol/app/AppProtocolHandler.cpp +++ b/netwerk/protocol/app/AppProtocolHandler.cpp @@ -316,11 +316,6 @@ NS_IMETHODIMP DummyChannel::GetContentDispositionHeader(nsACString&) return NS_ERROR_NOT_IMPLEMENTED; } -NS_IMETHODIMP DummyChannel::ForceNoIntercept() -{ - return NS_OK; -} - /** * app:// protocol implementation. */ From 92494c4d5f4f4a036f73d334d675e57e9e507ef2 Mon Sep 17 00:00:00 2001 From: Kaustabh Datta Choudhury Date: Tue, 6 Oct 2015 09:46:24 -0400 Subject: [PATCH 019/228] Bug 1162003 - Enable run-by-dir mode for mochitest_chrome on Fx desktop debug builds. r=jmaher --- docshell/test/chrome/chrome.ini | 2 +- js/xpconnect/tests/chrome/chrome.ini | 2 ++ testing/mochitest/runtests.py | 2 +- widget/tests/chrome.ini | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docshell/test/chrome/chrome.ini b/docshell/test/chrome/chrome.ini index 4b1e37c26030..3b752d2e9588 100644 --- a/docshell/test/chrome/chrome.ini +++ b/docshell/test/chrome/chrome.ini @@ -80,7 +80,7 @@ skip-if = os == 'linux' || os == 'mac' # Bug 1026815 [test_bug690056.xul] [test_bug789773.xul] [test_bug846906.xul] -skip-if = os == 'linux' && asan # Bug 1207161 +skip-if = (os == 'linux' && asan) || debug # Bug 1207161 [test_bug89419.xul] [test_bug909218.html] [test_bug92598.xul] diff --git a/js/xpconnect/tests/chrome/chrome.ini b/js/xpconnect/tests/chrome/chrome.ini index 8d6e167c88e3..003cbfab87d5 100644 --- a/js/xpconnect/tests/chrome/chrome.ini +++ b/js/xpconnect/tests/chrome/chrome.ini @@ -29,6 +29,7 @@ skip-if = buildapp == 'mulet' [test_bug614757.xul] [test_bug616992.xul] [test_bug618176.xul] +skip-if = os == 'win' && debug # Bug 1210863 [test_bug654370.xul] [test_bug658560.xul] [test_bug658909.xul] @@ -51,6 +52,7 @@ skip-if = buildapp == 'mulet' [test_bug793433.xul] [test_bug795275.xul] [test_bug799348.xul] +skip-if = os == 'win' && debug #Bug 1210876 [test_bug801241.xul] skip-if = buildapp == 'mulet' [test_bug812415.xul] diff --git a/testing/mochitest/runtests.py b/testing/mochitest/runtests.py index ec50289cdd9f..441f5658aeff 100644 --- a/testing/mochitest/runtests.py +++ b/testing/mochitest/runtests.py @@ -2592,7 +2592,7 @@ def run_test_harness(options): if runner.getTestFlavor(options) == 'browser-chrome': options.runByDir = True - if runner.getTestFlavor(options) == 'chrome' and (not mozinfo.info['debug']): + if runner.getTestFlavor(options) == 'chrome': options.runByDir = True if mozinfo.info.get('buildapp') == 'mulet': diff --git a/widget/tests/chrome.ini b/widget/tests/chrome.ini index 015119f84403..750e4c67c634 100644 --- a/widget/tests/chrome.ini +++ b/widget/tests/chrome.ini @@ -18,6 +18,7 @@ support-files = window_bug538242.xul [test_bug593307.xul] support-files = window_bug593307_offscreen.xul window_bug593307_centerscreen.xul [test_bug1151186.html] +skip-if = os == 'linux' && debug #Bug 1176038 [test_keycodes.xul] [test_wheeltransaction.xul] support-files = window_wheeltransaction.xul From d64ed1e12507e57bc1613662a4234d36d5f520fa Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Tue, 6 Oct 2015 14:50:49 +0100 Subject: [PATCH 020/228] Bug 1209585 - Fix possible memory leak if generating stub code fails with OOM r=jandem --HG-- extra : rebase_source : 2c2670f55ad0209e31ee164cf1abc16f6e25dbde --- js/src/jit-test/tests/baseline/bug1209585.js | 36 ++++++++++++++++++++ js/src/jit/BaselineIC.cpp | 11 +++--- js/src/jit/BaselineIC.h | 6 ++-- js/src/jit/SharedIC.cpp | 8 ++--- js/src/jit/SharedIC.h | 5 ++- 5 files changed, 49 insertions(+), 17 deletions(-) create mode 100644 js/src/jit-test/tests/baseline/bug1209585.js diff --git a/js/src/jit-test/tests/baseline/bug1209585.js b/js/src/jit-test/tests/baseline/bug1209585.js new file mode 100644 index 000000000000..b7e941731901 --- /dev/null +++ b/js/src/jit-test/tests/baseline/bug1209585.js @@ -0,0 +1,36 @@ +if (helperThreadCount() == 0) + quit(); + +if (!("oomAtAllocation" in this && "resetOOMFailure" in this)) + quit(); + +if ("gczeal" in this) + gczeal(0); + +eval("g=function() {}") +var lfGlobal = newGlobal(); +for (lfLocal in this) { + if (!(lfLocal in lfGlobal)) { + lfGlobal[lfLocal] = this[lfLocal]; + } +} +lfGlobal.offThreadCompileScript(` +if (!("oomAtAllocation" in this && "resetOOMFailure" in this)) + gczeal(0); +function oomTest(f) { + var i = 1; + do { + try { + oomAtAllocation(i); + f(); + more = resetOOMFailure(); + } catch (e) { + more = resetOOMFailure(); + } + i++; + } while(more); +} +var g = newGlobal(); +oomTest(function() { new revocable(); }); +`); +lfGlobal.runOffThreadScript(); diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 10d38260dff8..31526837828f 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -6210,13 +6210,12 @@ ICGetProp_Fallback::Compiler::generateStubCode(MacroAssembler& masm) return true; } -bool +void ICGetProp_Fallback::Compiler::postGenerateStubCode(MacroAssembler& masm, Handle code) { CodeOffsetLabel offset(returnOffset_); offset.fixup(&masm); cx->compartment()->jitCompartment()->initBaselineGetPropReturnAddr(code->raw() + offset.offset()); - return true; } bool @@ -7632,13 +7631,12 @@ ICSetProp_Fallback::Compiler::generateStubCode(MacroAssembler& masm) return true; } -bool +void ICSetProp_Fallback::Compiler::postGenerateStubCode(MacroAssembler& masm, Handle code) { CodeOffsetLabel offset(returnOffset_); offset.fixup(&masm); cx->compartment()->jitCompartment()->initBaselineSetPropReturnAddr(code->raw() + offset.offset()); - return true; } static void @@ -9403,17 +9401,16 @@ ICCall_Fallback::Compiler::generateStubCode(MacroAssembler& masm) return true; } -bool +void ICCall_Fallback::Compiler::postGenerateStubCode(MacroAssembler& masm, Handle code) { if (MOZ_UNLIKELY(isSpread_)) - return true; + return; CodeOffsetLabel offset(returnOffset_); offset.fixup(&masm); cx->compartment()->jitCompartment()->initBaselineCallReturnAddr(code->raw() + offset.offset(), isConstructing_); - return true; } typedef bool (*CreateThisFn)(JSContext* cx, HandleObject callee, MutableHandleValue rval); diff --git a/js/src/jit/BaselineIC.h b/js/src/jit/BaselineIC.h index f2efd0007b9c..0b1daffd56bd 100644 --- a/js/src/jit/BaselineIC.h +++ b/js/src/jit/BaselineIC.h @@ -2341,7 +2341,7 @@ class ICGetProp_Fallback : public ICMonitoredFallbackStub protected: uint32_t returnOffset_; bool generateStubCode(MacroAssembler& masm); - bool postGenerateStubCode(MacroAssembler& masm, Handle code); + void postGenerateStubCode(MacroAssembler& masm, Handle code); public: explicit Compiler(JSContext* cx) @@ -3334,7 +3334,7 @@ class ICSetProp_Fallback : public ICFallbackStub protected: uint32_t returnOffset_; bool generateStubCode(MacroAssembler& masm); - bool postGenerateStubCode(MacroAssembler& masm, Handle code); + void postGenerateStubCode(MacroAssembler& masm, Handle code); public: explicit Compiler(JSContext* cx) @@ -3941,7 +3941,7 @@ class ICCall_Fallback : public ICMonitoredFallbackStub bool isSpread_; uint32_t returnOffset_; bool generateStubCode(MacroAssembler& masm); - bool postGenerateStubCode(MacroAssembler& masm, Handle code); + void postGenerateStubCode(MacroAssembler& masm, Handle code); virtual int32_t getKey() const { return static_cast(engine_) | diff --git a/js/src/jit/SharedIC.cpp b/js/src/jit/SharedIC.cpp index ef88a01609c5..0d2f187bd9f1 100644 --- a/js/src/jit/SharedIC.cpp +++ b/js/src/jit/SharedIC.cpp @@ -719,10 +719,6 @@ ICStubCompiler::getStubCode() if (!newStubCode) return nullptr; - // After generating code, run postGenerateStubCode() - if (!postGenerateStubCode(masm, newStubCode)) - return nullptr; - // All barriers are emitted off-by-default, enable them if needed. if (cx->zone()->needsIncrementalBarrier()) newStubCode->togglePreBarriers(true); @@ -731,6 +727,10 @@ ICStubCompiler::getStubCode() if (!comp->putStubCode(cx, stubKey, newStubCode)) return nullptr; + // After generating code, run postGenerateStubCode(). We must not fail + // after this point. + postGenerateStubCode(masm, newStubCode); + MOZ_ASSERT(entersStubFrame_ == ICStub::CanMakeCalls(kind)); MOZ_ASSERT(!inStubFrame_); diff --git a/js/src/jit/SharedIC.h b/js/src/jit/SharedIC.h index 4d8f46f8d3d0..10189036d1e6 100644 --- a/js/src/jit/SharedIC.h +++ b/js/src/jit/SharedIC.h @@ -997,9 +997,8 @@ class ICStubCompiler } virtual bool generateStubCode(MacroAssembler& masm) = 0; - virtual bool postGenerateStubCode(MacroAssembler& masm, Handle genCode) { - return true; - } + virtual void postGenerateStubCode(MacroAssembler& masm, Handle genCode) {} + JitCode* getStubCode(); ICStubCompiler(JSContext* cx, ICStub::Kind kind, Engine engine) From 5ea571ddb75f06d855fe2cd01b4c0320a3ae05cd Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Tue, 6 Oct 2015 14:50:49 +0100 Subject: [PATCH 021/228] Bug 1211100 - Add Vector::infallibleEmplaceBack and use it in JSScript::initScriptCounts() r=nbp --HG-- extra : rebase_source : a989ddba0bc981725a955c705a51aa495ef59ab9 --- js/src/jsscript.cpp | 2 +- mfbt/Vector.h | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index f91f08d1a66f..3c8d26b889f7 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -1334,7 +1334,7 @@ JSScript::initScriptCounts(JSContext* cx) return false; for (size_t i = 0; i < jumpTargets.length(); i++) - MOZ_ALWAYS_TRUE(base.emplaceBack(pcToOffset(jumpTargets[i]))); + base.infallibleEmplaceBack(pcToOffset(jumpTargets[i])); // Create compartment's scriptCountsMap if necessary. ScriptCountsMap* map = compartment()->scriptCountsMap; diff --git a/mfbt/Vector.h b/mfbt/Vector.h index 7f507ef5c3f3..d18bfa70bd5c 100644 --- a/mfbt/Vector.h +++ b/mfbt/Vector.h @@ -603,6 +603,12 @@ public: { internalAppend(aBegin, aLength); } + template + void infallibleEmplaceBack(Args&&... aArgs) + { + infallibleGrowByUninitialized(1); + new (&back()) T(Forward(aArgs)...); + } void popBack(); From 810fbfb206e5ff9b080894a0e1e7df2387197fab Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Tue, 6 Oct 2015 14:50:49 +0100 Subject: [PATCH 022/228] Bug 1209911 - Make AutoEnterOOMUnsafeRegion ignore threads that are not simulating OOM r=terrence --HG-- extra : rebase_source : 99b217832f10946adf18896a1bb064092bb0b7fd --- js/public/Utility.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/js/public/Utility.h b/js/public/Utility.h index 3279b0c23f4f..6e635201e476 100644 --- a/js/public/Utility.h +++ b/js/public/Utility.h @@ -84,7 +84,6 @@ enum ThreadType { THREAD_TYPE_MAX // Used to check shell function arguments }; - /* * Getter/Setter functions to encapsulate mozilla::ThreadLocal, * implementation is in jsutil.cpp. @@ -126,23 +125,22 @@ namespace oom { extern JS_PUBLIC_DATA(uint32_t) targetThread; static inline bool -OOMThreadCheck() +IsThreadSimulatingOOM() { - return (!js::oom::targetThread - || js::oom::targetThread == js::oom::GetThreadType()); + return !js::oom::targetThread || js::oom::targetThread == js::oom::GetThreadType(); } static inline bool IsSimulatedOOMAllocation() { - return OOMThreadCheck() && (OOM_counter == OOM_maxAllocations || + return IsThreadSimulatingOOM() && (OOM_counter == OOM_maxAllocations || (OOM_counter > OOM_maxAllocations && OOM_failAlways)); } static inline bool ShouldFailWithOOM() { - if (!OOMThreadCheck()) + if (!IsThreadSimulatingOOM()) return false; OOM_counter++; @@ -195,7 +193,8 @@ struct MOZ_RAII AutoEnterOOMUnsafeRegion #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) AutoEnterOOMUnsafeRegion() - : oomEnabled_(OOM_maxAllocations != UINT32_MAX), oomAfter_(0) + : oomEnabled_(oom::IsThreadSimulatingOOM() && OOM_maxAllocations != UINT32_MAX), + oomAfter_(0) { if (oomEnabled_) { oomAfter_ = int64_t(OOM_maxAllocations) - OOM_counter; From 298b347ff45aee1713b4bcfd0ec40a4b8f5a7097 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Tue, 6 Oct 2015 14:50:49 +0100 Subject: [PATCH 023/228] Bug 1209911 - Add oomThreadTypes() test function to report the number of thread types we can simulate OOM on r=terrence --HG-- extra : rebase_source : facfa7ff892375e7c5999cd9310948866542e2f9 --- js/src/builtin/TestingFunctions.cpp | 13 +++++++++ js/src/jit-test/lib/oomTest.js | 43 ++++++++++++++++------------- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 7312fe332c5c..883362879091 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -984,6 +984,14 @@ DisableTrackAllocations(JSContext* cx, unsigned argc, Value* vp) } #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) +static bool +OOMThreadTypes(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + args.rval().setInt32(js::oom::THREAD_TYPE_MAX); + return true; +} + static bool OOMAfterAllocations(JSContext* cx, unsigned argc, Value* vp) { @@ -2928,6 +2936,11 @@ static const JSFunctionSpecWithHelp TestingFunctions[] = { " Stop capturing the JS stack at every allocation."), #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) + JS_FN_HELP("oomThreadTypes", OOMThreadTypes, 0, 0, +"oomThreadTypes()", +" Get the number of thread types that can be used as an argument for\n" +"oomAfterAllocations() and oomAtAllocation()."), + JS_FN_HELP("oomAfterAllocations", OOMAfterAllocations, 2, 0, "oomAfterAllocations(count [,threadType])", " After 'count' js_malloc memory allocations, fail every following allocation\n" diff --git a/js/src/jit-test/lib/oomTest.js b/js/src/jit-test/lib/oomTest.js index 5536855c62d9..75e6d49219d1 100644 --- a/js/src/jit-test/lib/oomTest.js +++ b/js/src/jit-test/lib/oomTest.js @@ -1,34 +1,39 @@ // Function to test OOM handling by repeatedly calling a function and failing // successive allocations. -const verbose = false; - -if (!("oomAtAllocation" in this && "resetOOMFailure" in this)) +if (!("oomAtAllocation" in this && "resetOOMFailure" in this && "oomThreadTypes" in this)) quit(); if ("gczeal" in this) gczeal(0); +const verbose = ("os" in this) && os.getenv("OOM_VERBOSE"); + // Test out of memory handing by calling a function f() while causing successive // memory allocations to fail. Repeat until f() finishes without reaching the // failing allocation. function oomTest(f) { - var i = 1; - var more; - do { + for (let thread = 1; thread < oomThreadTypes(); thread++) { if (verbose) - print("fail at " + i); - try { - oomAtAllocation(i); - f(); - more = resetOOMFailure(); - } catch (e) { - // Ignore exceptions. - more = resetOOMFailure(); - } - i++; - } while(more); + print("testing thread " + thread); - if (verbose) - print("finished after " + i); + var i = 1; + var more; + do { + if (verbose) + print("fail at " + i); + try { + oomAtAllocation(i, thread); + f(); + more = resetOOMFailure(); + } catch (e) { + // Ignore exceptions. + more = resetOOMFailure(); + } + i++; + } while(more); + + if (verbose) + print("finished after " + (i - 2) + " failures"); + } } From 55207dee47b718531930fb621650a86597193c11 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Tue, 6 Oct 2015 14:50:49 +0100 Subject: [PATCH 024/228] Bug 1209911 - Use a Variant type to represent HelperThread data r=jandem --HG-- extra : rebase_source : 42fcdd9ea5d97a435ecae93a73c430282695a2f7 --- js/src/vm/HelperThreads.cpp | 121 ++++++++++++++++++------------------ js/src/vm/HelperThreads.h | 77 +++++++++++++++-------- 2 files changed, 113 insertions(+), 85 deletions(-) diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index acf9c0b56945..048ee0cdeabe 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -155,10 +155,10 @@ js::CancelOffThreadIonCompile(JSCompartment* compartment, JSScript* script) /* Wait for in progress entries to finish up. */ for (size_t i = 0; i < HelperThreadState().threadCount; i++) { HelperThread& helper = HelperThreadState().threads[i]; - while (helper.ionBuilder && - CompiledScriptMatches(compartment, script, helper.ionBuilder->script())) + while (helper.ionBuilder() && + CompiledScriptMatches(compartment, script, helper.ionBuilder()->script())) { - helper.ionBuilder->cancel(); + helper.ionBuilder()->cancel(); if (helper.pause) { helper.pause = false; HelperThreadState().notifyAll(GlobalHelperThreadState::PAUSE); @@ -274,7 +274,7 @@ js::CancelOffThreadParses(JSRuntime* rt) if (!pending) { bool inProgress = false; for (size_t i = 0; i < HelperThreadState().threadCount; i++) { - ParseTask* task = HelperThreadState().threads[i].parseTask; + ParseTask* task = HelperThreadState().threads[i].parseTask(); if (task && task->runtimeMatches(rt)) inProgress = true; } @@ -630,7 +630,7 @@ GlobalHelperThreadState::canStartAsmJSCompile() // to avoid oversaturating the machine. size_t numAsmJSThreads = 0; for (size_t i = 0; i < threadCount; i++) { - if (threads[i].asmData) + if (threads[i].asmJSTask()) numAsmJSThreads++; } if (numAsmJSThreads >= maxAsmJSCompilationThreads()) @@ -697,9 +697,9 @@ GlobalHelperThreadState::lowestPriorityUnpausedIonCompileAtThreshold() size_t numBuilderThreads = 0; HelperThread* thread = nullptr; for (size_t i = 0; i < threadCount; i++) { - if (threads[i].ionBuilder && !threads[i].pause) { + if (threads[i].ionBuilder() && !threads[i].pause) { numBuilderThreads++; - if (!thread || IonBuilderHasHigherPriority(thread->ionBuilder, threads[i].ionBuilder)) + if (!thread || IonBuilderHasHigherPriority(thread->ionBuilder(), threads[i].ionBuilder())) thread = &threads[i]; } } @@ -719,8 +719,8 @@ GlobalHelperThreadState::highestPriorityPausedIonCompile() for (size_t i = 0; i < threadCount; i++) { if (threads[i].pause) { // Currently, only threads with IonBuilders can be paused. - MOZ_ASSERT(threads[i].ionBuilder); - if (!thread || IonBuilderHasHigherPriority(threads[i].ionBuilder, thread->ionBuilder)) + MOZ_ASSERT(threads[i].ionBuilder()); + if (!thread || IonBuilderHasHigherPriority(threads[i].ionBuilder(), thread->ionBuilder())) thread = &threads[i]; } } @@ -748,7 +748,8 @@ GlobalHelperThreadState::pendingIonCompileHasSufficientPriority() // If there is a builder in the worklist with higher priority than some // builder currently being compiled, then that current compilation can be // paused, so allow the compilation. - if (IonBuilderHasHigherPriority(highestPriorityPendingIonCompile(), lowestPriorityThread->ionBuilder)) + if (IonBuilderHasHigherPriority(highestPriorityPendingIonCompile(), + lowestPriorityThread->ionBuilder())) return true; // Compilation will have to wait until one of the active compilations finishes. @@ -766,7 +767,7 @@ GlobalHelperThreadState::canStartParseTask() if (parseWorklist().empty()) return false; for (size_t i = 0; i < threadCount; i++) { - if (threads[i].parseTask) + if (threads[i].parseTask()) return false; } return true; @@ -893,10 +894,9 @@ HelperThread::handleGCParallelWorkload() MOZ_ASSERT(HelperThreadState().canStartGCParallelTask()); MOZ_ASSERT(idle()); - MOZ_ASSERT(!gcParallelTask); - gcParallelTask = HelperThreadState().gcParallelWorklist().popCopy(); - gcParallelTask->runFromHelperThread(); - gcParallelTask = nullptr; + currentTask.emplace(HelperThreadState().gcParallelWorklist().popCopy()); + gcParallelTask()->runFromHelperThread(); + currentTask.reset(); } static void @@ -1094,9 +1094,10 @@ HelperThread::handleAsmJSWorkload() MOZ_ASSERT(HelperThreadState().canStartAsmJSCompile()); MOZ_ASSERT(idle()); - asmData = HelperThreadState().asmJSWorklist().popCopy(); + currentTask.emplace(HelperThreadState().asmJSWorklist().popCopy()); bool success = false; + AsmJSParallelTask* asmData = asmJSTask(); do { AutoUnlockHelperThreadState unlock; PerThreadData::AutoEnterRuntime enter(threadData.ptr(), asmData->runtime); @@ -1129,13 +1130,13 @@ HelperThread::handleAsmJSWorkload() if (!success) { HelperThreadState().noteAsmJSFailure(asmData->func); HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER); - asmData = nullptr; + currentTask.reset(); return; } // Notify the main thread in case it's blocked waiting for a LifoAlloc. HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER); - asmData = nullptr; + currentTask.reset(); } void @@ -1156,32 +1157,32 @@ HelperThread::handleIonWorkload() // was called, the builder we are pausing may actually be higher priority // than the one we are about to start. Oh well. if (HelperThread* other = HelperThreadState().lowestPriorityUnpausedIonCompileAtThreshold()) { - MOZ_ASSERT(other->ionBuilder && !other->pause); + MOZ_ASSERT(other->ionBuilder() && !other->pause); other->pause = true; } - ionBuilder = builder; - ionBuilder->setPauseFlag(&pause); + currentTask.emplace(builder); + builder->setPauseFlag(&pause); TraceLoggerThread* logger = TraceLoggerForCurrentThread(); - TraceLoggerEvent event(logger, TraceLogger_AnnotateScripts, ionBuilder->script()); + TraceLoggerEvent event(logger, TraceLogger_AnnotateScripts, builder->script()); AutoTraceLog logScript(logger, event); AutoTraceLog logCompile(logger, TraceLogger_IonCompilation); - JSRuntime* rt = ionBuilder->script()->compartment()->runtimeFromAnyThread(); + JSRuntime* rt = builder->script()->compartment()->runtimeFromAnyThread(); { AutoUnlockHelperThreadState unlock; PerThreadData::AutoEnterRuntime enter(threadData.ptr(), - ionBuilder->script()->runtimeFromAnyThread()); + builder->script()->runtimeFromAnyThread()); jit::JitContext jctx(jit::CompileRuntime::get(rt), - jit::CompileCompartment::get(ionBuilder->script()->compartment()), - &ionBuilder->alloc()); - ionBuilder->setBackgroundCodegen(jit::CompileBackEnd(ionBuilder)); + jit::CompileCompartment::get(builder->script()->compartment()), + &builder->alloc()); + builder->setBackgroundCodegen(jit::CompileBackEnd(builder)); } - FinishOffThreadIonCompile(ionBuilder); - ionBuilder = nullptr; + FinishOffThreadIonCompile(builder); + currentTask.reset(); pause = false; // Ping the main thread so that the compiled code can be incorporated @@ -1201,12 +1202,12 @@ HelperThread::handleIonWorkload() // many there are, since each thread we unpause will eventually finish and // end up back here. if (HelperThread* other = HelperThreadState().highestPriorityPausedIonCompile()) { - MOZ_ASSERT(other->ionBuilder && other->pause); + MOZ_ASSERT(other->ionBuilder() && other->pause); // Only unpause the other thread if there isn't a higher priority // builder which this thread or another can start on. jit::IonBuilder* builder = HelperThreadState().highestPriorityPendingIonCompile(); - if (!builder || IonBuilderHasHigherPriority(other->ionBuilder, builder)) { + if (!builder || IonBuilderHasHigherPriority(other->ionBuilder(), builder)) { other->pause = false; // Notify all paused threads, to make sure the one we just @@ -1257,7 +1258,7 @@ ExclusiveContext::addPendingCompileError() frontend::CompileError* error = js_new(); if (!error) MOZ_CRASH(); - if (!helperThread()->parseTask->errors.append(error)) + if (!helperThread()->parseTask()->errors.append(error)) MOZ_CRASH(); return *error; } @@ -1265,8 +1266,8 @@ ExclusiveContext::addPendingCompileError() void ExclusiveContext::addPendingOverRecursed() { - if (helperThread()->parseTask) - helperThread()->parseTask->overRecursed = true; + if (helperThread()->parseTask()) + helperThread()->parseTask()->overRecursed = true; } void @@ -1276,33 +1277,34 @@ HelperThread::handleParseWorkload() MOZ_ASSERT(HelperThreadState().canStartParseTask()); MOZ_ASSERT(idle()); - parseTask = HelperThreadState().parseWorklist().popCopy(); - parseTask->cx->setHelperThread(this); + currentTask.emplace(HelperThreadState().parseWorklist().popCopy()); + ParseTask* task = parseTask(); + task->cx->setHelperThread(this); { AutoUnlockHelperThreadState unlock; PerThreadData::AutoEnterRuntime enter(threadData.ptr(), - parseTask->exclusiveContextGlobal->runtimeFromAnyThread()); - SourceBufferHolder srcBuf(parseTask->chars, parseTask->length, + task->exclusiveContextGlobal->runtimeFromAnyThread()); + SourceBufferHolder srcBuf(task->chars, task->length, SourceBufferHolder::NoOwnership); - parseTask->script = frontend::CompileScript(parseTask->cx, &parseTask->alloc, - nullptr, nullptr, nullptr, - parseTask->options, - srcBuf, - /* source_ = */ nullptr, - /* extraSct = */ nullptr, - /* sourceObjectOut = */ &(parseTask->sourceObject)); + task->script = frontend::CompileScript(task->cx, &task->alloc, + nullptr, nullptr, nullptr, + task->options, + srcBuf, + /* source_ = */ nullptr, + /* extraSct = */ nullptr, + /* sourceObjectOut = */ &(task->sourceObject)); } // The callback is invoked while we are still off the main thread. - parseTask->callback(parseTask, parseTask->callbackData); + task->callback(task, task->callbackData); // FinishOffThreadScript will need to be called on the script to // migrate it into the correct compartment. - if (!HelperThreadState().parseFinishedList().append(parseTask)) + if (!HelperThreadState().parseFinishedList().append(task)) CrashAtUnhandlableOOM("handleParseWorkload"); - parseTask = nullptr; + currentTask.reset(); // Notify the main thread in case it is waiting for the parse/emit to finish. HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER); @@ -1315,16 +1317,17 @@ HelperThread::handleCompressionWorkload() MOZ_ASSERT(HelperThreadState().canStartCompressionTask()); MOZ_ASSERT(idle()); - compressionTask = HelperThreadState().compressionWorklist().popCopy(); - compressionTask->helperThread = this; + currentTask.emplace(HelperThreadState().compressionWorklist().popCopy()); + SourceCompressionTask* task = compressionTask(); + task->helperThread = this; { AutoUnlockHelperThreadState unlock; - compressionTask->result = compressionTask->work(); + task->result = task->work(); } - compressionTask->helperThread = nullptr; - compressionTask = nullptr; + task->helperThread = nullptr; + currentTask.reset(); // Notify the main thread in case it is waiting for the compression to finish. HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER); @@ -1354,7 +1357,7 @@ GlobalHelperThreadState::compressionInProgress(SourceCompressionTask* task) return true; } for (size_t i = 0; i < threadCount; i++) { - if (threads[i].compressionTask == task) + if (threads[i].compressionTask() == task) return true; } return false; @@ -1406,7 +1409,7 @@ GlobalHelperThreadState::compressionTaskForSource(ScriptSource* ss) return task; } for (size_t i = 0; i < threadCount; i++) { - SourceCompressionTask* task = threads[i].compressionTask; + SourceCompressionTask* task = threads[i].compressionTask(); if (task && task->source() == ss) return task; } @@ -1420,15 +1423,15 @@ HelperThread::handleGCHelperWorkload() MOZ_ASSERT(HelperThreadState().canStartGCHelperTask()); MOZ_ASSERT(idle()); - MOZ_ASSERT(!gcHelperState); - gcHelperState = HelperThreadState().gcHelperWorklist().popCopy(); + currentTask.emplace(HelperThreadState().gcHelperWorklist().popCopy()); + GCHelperState* task = gcHelperTask(); { AutoUnlockHelperThreadState unlock; - gcHelperState->work(); + task->work(); } - gcHelperState = nullptr; + currentTask.reset(); } void diff --git a/js/src/vm/HelperThreads.h b/js/src/vm/HelperThreads.h index 0c22485f43a5..c6e6652bdaba 100644 --- a/js/src/vm/HelperThreads.h +++ b/js/src/vm/HelperThreads.h @@ -15,6 +15,7 @@ #include "mozilla/GuardObjects.h" #include "mozilla/PodOperations.h" +#include "mozilla/Variant.h" #include "jscntxt.h" #include "jslock.h" @@ -299,44 +300,68 @@ struct HelperThread */ mozilla::Atomic pause; - /* Any builder currently being compiled by Ion on this thread. */ - jit::IonBuilder* ionBuilder; - - /* Any AsmJS data currently being optimized by Ion on this thread. */ - AsmJSParallelTask* asmData; - - /* Any source being parsed/emitted on this thread. */ - ParseTask* parseTask; - - /* Any source being compressed on this thread. */ - SourceCompressionTask* compressionTask; - - /* Any GC state for background sweeping or allocating being performed. */ - GCHelperState* gcHelperState; - - /* State required to perform a GC parallel task. */ - GCParallelTask* gcParallelTask; + /* The current task being executed by this thread, if any. */ + mozilla::Maybe> currentTask; bool idle() const { - return !ionBuilder && - !asmData && - !parseTask && - !compressionTask && - !gcHelperState && - !gcParallelTask; + return currentTask.isNothing(); + } + + /* Any builder currently being compiled by Ion on this thread. */ + jit::IonBuilder* ionBuilder() { + return maybeCurrentTaskAs(); + } + + /* Any AsmJS data currently being optimized by Ion on this thread. */ + AsmJSParallelTask* asmJSTask() { + return maybeCurrentTaskAs(); + } + + /* Any source being parsed/emitted on this thread. */ + ParseTask* parseTask() { + return maybeCurrentTaskAs(); + } + + /* Any source being compressed on this thread. */ + SourceCompressionTask* compressionTask() { + return maybeCurrentTaskAs(); + } + + /* Any GC state for background sweeping or allocating being performed. */ + GCHelperState* gcHelperTask() { + return maybeCurrentTaskAs(); + } + + /* State required to perform a GC parallel task. */ + GCParallelTask* gcParallelTask() { + return maybeCurrentTaskAs(); } void destroy(); + static void ThreadMain(void* arg); + void threadLoop(); + + private: + template + T maybeCurrentTaskAs() { + if (currentTask.isSome() && currentTask->is()) + return currentTask->as(); + + return nullptr; + } + void handleAsmJSWorkload(); void handleIonWorkload(); void handleParseWorkload(); void handleCompressionWorkload(); void handleGCHelperWorkload(); void handleGCParallelWorkload(); - - static void ThreadMain(void* arg); - void threadLoop(); }; /* Methods for interacting with helper threads. */ From f3fb1958bf44d04cd9b25eafbe72e8affed40de4 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Tue, 6 Oct 2015 14:50:50 +0100 Subject: [PATCH 025/228] Bug 1209911 - Limit the number of helper threads of a particular type when simulating OOM r=jandem --HG-- extra : rebase_source : 4313e2f5c109c91ef047483bfa157ff4505b4855 --- js/src/builtin/TestingFunctions.cpp | 2 + js/src/vm/HelperThreads.cpp | 158 +++++++++++++++++++++++----- js/src/vm/HelperThreads.h | 21 ++-- 3 files changed, 147 insertions(+), 34 deletions(-) diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 883362879091..35133f06e24f 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -1019,6 +1019,7 @@ OOMAfterAllocations(JSContext* cx, unsigned argc, Value* vp) if (!JS::ToUint32(cx, args.get(0), &count)) return false; + HelperThreadState().waitForAllThreads(); js::oom::targetThread = targetThread; OOM_maxAllocations = OOM_counter + count; OOM_failAlways = true; @@ -1052,6 +1053,7 @@ OOMAtAllocation(JSContext* cx, unsigned argc, Value* vp) if (!JS::ToUint32(cx, args.get(0), &count)) return false; + HelperThreadState().waitForAllThreads(); js::oom::targetThread = targetThread; OOM_maxAllocations = OOM_counter + count; OOM_failAlways = false; diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index 048ee0cdeabe..fc7d292d3dbb 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -127,14 +127,15 @@ CompiledScriptMatches(JSCompartment* compartment, JSScript* script, JSScript* ta { if (script) return target == script; - return target->compartment() == compartment; + if (compartment) + return target->compartment() == compartment; + return true; } void js::CancelOffThreadIonCompile(JSCompartment* compartment, JSScript* script) { - jit::JitCompartment* jitComp = compartment->jitCompartment(); - if (!jitComp) + if (compartment && !compartment->jitCompartment()) return; AutoLockHelperThreadState lock; @@ -618,6 +619,120 @@ GlobalHelperThreadState::notifyOne(CondVar which) PR_NotifyCondVar(whichWakeup(which)); } +bool +GlobalHelperThreadState::hasActiveThreads() +{ + MOZ_ASSERT(isLocked()); + if (!threads) + return false; + + for (size_t i = 0; i < threadCount; i++) { + if (!threads[i].idle()) + return true; + } + + return false; +} + +void +GlobalHelperThreadState::waitForAllThreads() +{ + CancelOffThreadIonCompile(nullptr, nullptr); + + AutoLockHelperThreadState lock; + while (hasActiveThreads()) + wait(CONSUMER); +} + +template +bool +GlobalHelperThreadState::checkTaskThreadLimit(size_t maxThreads) const +{ + if (maxThreads >= threadCount) + return true; + + size_t count = 0; + for (size_t i = 0; i < threadCount; i++) { + if (threads[i].currentTask.isSome() && threads[i].currentTask->is()) + count++; + if (count >= maxThreads) + return false; + } + + return true; +} + +static inline bool +IsHelperThreadSimulatingOOM(js::oom::ThreadType threadType) +{ +#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) + return js::oom::targetThread == threadType; +#else + return false; +#endif +} + +size_t +GlobalHelperThreadState::maxIonCompilationThreads() const +{ + if (IsHelperThreadSimulatingOOM(js::oom::THREAD_TYPE_ION)) + return 1; + return threadCount; +} + +size_t +GlobalHelperThreadState::maxUnpausedIonCompilationThreads() const +{ + return 1; +} + +size_t +GlobalHelperThreadState::maxAsmJSCompilationThreads() const +{ + if (IsHelperThreadSimulatingOOM(js::oom::THREAD_TYPE_ASMJS)) + return 1; + if (cpuCount < 2) + return 2; + return cpuCount; +} + +size_t +GlobalHelperThreadState::maxParseThreads() const +{ + if (IsHelperThreadSimulatingOOM(js::oom::THREAD_TYPE_PARSE)) + return 1; + + // Don't allow simultaneous off thread parses, to reduce contention on the + // atoms table. Note that asm.js compilation depends on this to avoid + // stalling the helper thread, as off thread parse tasks can trigger and + // block on other off thread asm.js compilation tasks. + return 1; +} + +size_t +GlobalHelperThreadState::maxCompressionThreads() const +{ + if (IsHelperThreadSimulatingOOM(js::oom::THREAD_TYPE_COMPRESS)) + return 1; + return threadCount; +} + +size_t +GlobalHelperThreadState::maxGCHelperThreads() const +{ + if (IsHelperThreadSimulatingOOM(js::oom::THREAD_TYPE_GCHELPER)) + return 1; + return threadCount; +} + +size_t +GlobalHelperThreadState::maxGCParallelThreads() const +{ + if (IsHelperThreadSimulatingOOM(js::oom::THREAD_TYPE_GCPARALLEL)) + return 1; + return threadCount; +} + bool GlobalHelperThreadState::canStartAsmJSCompile() { @@ -628,12 +743,7 @@ GlobalHelperThreadState::canStartAsmJSCompile() // Honor the maximum allowed threads to compile AsmJS jobs at once, // to avoid oversaturating the machine. - size_t numAsmJSThreads = 0; - for (size_t i = 0; i < threadCount; i++) { - if (threads[i].asmJSTask()) - numAsmJSThreads++; - } - if (numAsmJSThreads >= maxAsmJSCompilationThreads()) + if (!checkTaskThreadLimit(maxAsmJSCompilationThreads())) return false; return true; @@ -661,7 +771,8 @@ IonBuilderHasHigherPriority(jit::IonBuilder* first, jit::IonBuilder* second) bool GlobalHelperThreadState::canStartIonCompile() { - return !ionWorklist().empty(); + return !ionWorklist().empty() && + checkTaskThreadLimit(maxIonCompilationThreads()); } jit::IonBuilder* @@ -692,7 +803,7 @@ GlobalHelperThreadState::lowestPriorityUnpausedIonCompileAtThreshold() MOZ_ASSERT(isLocked()); // Get the lowest priority IonBuilder which has started compilation and - // isn't paused, unless there are still fewer than the aximum number of + // isn't paused, unless there are still fewer than the maximum number of // such builders permitted. size_t numBuilderThreads = 0; HelperThread* thread = nullptr; @@ -703,7 +814,7 @@ GlobalHelperThreadState::lowestPriorityUnpausedIonCompileAtThreshold() thread = &threads[i]; } } - if (numBuilderThreads < maxIonCompilationThreads()) + if (numBuilderThreads < maxUnpausedIonCompilationThreads()) return nullptr; return thread; } @@ -759,36 +870,29 @@ GlobalHelperThreadState::pendingIonCompileHasSufficientPriority() bool GlobalHelperThreadState::canStartParseTask() { - // Don't allow simultaneous off thread parses, to reduce contention on the - // atoms table. Note that asm.js compilation depends on this to avoid - // stalling the helper thread, as off thread parse tasks can trigger and - // block on other off thread asm.js compilation tasks. MOZ_ASSERT(isLocked()); - if (parseWorklist().empty()) - return false; - for (size_t i = 0; i < threadCount; i++) { - if (threads[i].parseTask()) - return false; - } - return true; + return !parseWorklist().empty() && checkTaskThreadLimit(maxParseThreads()); } bool GlobalHelperThreadState::canStartCompressionTask() { - return !compressionWorklist().empty(); + return !compressionWorklist().empty() && + checkTaskThreadLimit(maxCompressionThreads()); } bool GlobalHelperThreadState::canStartGCHelperTask() { - return !gcHelperWorklist().empty(); + return !gcHelperWorklist().empty() && + checkTaskThreadLimit(maxGCHelperThreads()); } bool GlobalHelperThreadState::canStartGCParallelTask() { - return !gcParallelWorklist().empty(); + return !gcParallelWorklist().empty() && + checkTaskThreadLimit(maxGCParallelThreads()); } js::GCParallelTask::~GCParallelTask() @@ -897,6 +1001,7 @@ HelperThread::handleGCParallelWorkload() currentTask.emplace(HelperThreadState().gcParallelWorklist().popCopy()); gcParallelTask()->runFromHelperThread(); currentTask.reset(); + HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER); } static void @@ -1432,6 +1537,7 @@ HelperThread::handleGCHelperWorkload() } currentTask.reset(); + HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER); } void diff --git a/js/src/vm/HelperThreads.h b/js/src/vm/HelperThreads.h index c6e6652bdaba..aa54be6d6245 100644 --- a/js/src/vm/HelperThreads.h +++ b/js/src/vm/HelperThreads.h @@ -93,14 +93,13 @@ class GlobalHelperThreadState GCParallelTaskVector gcParallelWorklist_; public: - size_t maxIonCompilationThreads() const { - return 1; - } - size_t maxAsmJSCompilationThreads() const { - if (cpuCount < 2) - return 2; - return cpuCount; - } + size_t maxIonCompilationThreads() const; + size_t maxUnpausedIonCompilationThreads() const; + size_t maxAsmJSCompilationThreads() const; + size_t maxParseThreads() const; + size_t maxCompressionThreads() const; + size_t maxGCHelperThreads() const; + size_t maxGCParallelThreads() const; GlobalHelperThreadState(); @@ -236,6 +235,12 @@ class GlobalHelperThreadState bool compressionInProgress(SourceCompressionTask* task); SourceCompressionTask* compressionTaskForSource(ScriptSource* ss); + bool hasActiveThreads(); + void waitForAllThreads(); + + template + bool checkTaskThreadLimit(size_t maxThreads) const; + private: /* From a758f199260b97654afb432834360dbee8c618dd Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Tue, 6 Oct 2015 14:50:50 +0100 Subject: [PATCH 026/228] Bug 1209911 - Remove option to simulate OOM on all threads r=terrence --HG-- extra : rebase_source : c03694b314165446ffa3a6ab4d70fea02c202055 --- js/public/Utility.h | 9 ++--- js/src/builtin/TestingFunctions.cpp | 63 ++++++++++------------------- 2 files changed, 24 insertions(+), 48 deletions(-) diff --git a/js/public/Utility.h b/js/public/Utility.h index 6e635201e476..5b36e5eec0b0 100644 --- a/js/public/Utility.h +++ b/js/public/Utility.h @@ -73,7 +73,7 @@ namespace oom { * without causing an OOM in the main thread first. */ enum ThreadType { - THREAD_TYPE_NONE, // 0 + THREAD_TYPE_NONE = 0, // 0 THREAD_TYPE_MAIN, // 1 THREAD_TYPE_ASMJS, // 2 THREAD_TYPE_ION, // 3 @@ -127,7 +127,7 @@ extern JS_PUBLIC_DATA(uint32_t) targetThread; static inline bool IsThreadSimulatingOOM() { - return !js::oom::targetThread || js::oom::targetThread == js::oom::GetThreadType(); + return js::oom::targetThread && js::oom::targetThread == js::oom::GetThreadType(); } static inline bool @@ -203,11 +203,8 @@ struct MOZ_RAII AutoEnterOOMUnsafeRegion } ~AutoEnterOOMUnsafeRegion() { - // TODO: This class is not thread safe. If another thread has modified - // OOM_maxAllocations, don't try to restore it. - if (OOM_maxAllocations != UINT32_MAX) - return; if (oomEnabled_) { + MOZ_ASSERT(OOM_maxAllocations == UINT32_MAX); int64_t maxAllocations = OOM_counter + oomAfter_; MOZ_ASSERT(maxAllocations >= 0 && maxAllocations < UINT32_MAX); OOM_maxAllocations = uint32_t(maxAllocations); diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 35133f06e24f..edf6e318309f 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -993,25 +993,16 @@ OOMThreadTypes(JSContext* cx, unsigned argc, Value* vp) } static bool -OOMAfterAllocations(JSContext* cx, unsigned argc, Value* vp) +SetupOOMFailure(JSContext* cx, bool failAlways, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); if (args.length() < 1) { - JS_ReportError(cx, "count argument required"); + JS_ReportError(cx, "Count argument required"); return false; } if (args.length() > 2) { - JS_ReportError(cx, "too many arguments"); - return false; - } - - uint32_t targetThread = 0; - if (!ToUint32(cx, args.get(1), &targetThread)) - return false; - - if (targetThread >= js::oom::THREAD_TYPE_MAX) { - JS_ReportError(cx, "invalid thread type specified"); + JS_ReportError(cx, "Too many arguments"); return false; } @@ -1019,45 +1010,32 @@ OOMAfterAllocations(JSContext* cx, unsigned argc, Value* vp) if (!JS::ToUint32(cx, args.get(0), &count)) return false; + uint32_t targetThread = js::oom::THREAD_TYPE_MAIN; + if (args.length() > 1 && !ToUint32(cx, args[1], &targetThread)) + return false; + + if (targetThread == js::oom::THREAD_TYPE_NONE || targetThread >= js::oom::THREAD_TYPE_MAX) { + JS_ReportError(cx, "Invalid thread type specified"); + return false; + } + HelperThreadState().waitForAllThreads(); js::oom::targetThread = targetThread; OOM_maxAllocations = OOM_counter + count; - OOM_failAlways = true; + OOM_failAlways = failAlways; return true; } +static bool +OOMAfterAllocations(JSContext* cx, unsigned argc, Value* vp) +{ + return SetupOOMFailure(cx, true, argc, vp); +} + static bool OOMAtAllocation(JSContext* cx, unsigned argc, Value* vp) { - CallArgs args = CallArgsFromVp(argc, vp); - if (args.length() < 1) { - JS_ReportError(cx, "count argument required"); - return false; - } - - if (args.length() > 2) { - JS_ReportError(cx, "too many arguments"); - return false; - } - - uint32_t targetThread = 0; - if (!ToUint32(cx, args.get(1), &targetThread)) - return false; - - if (targetThread >= js::oom::THREAD_TYPE_MAX) { - JS_ReportError(cx, "invalid thread type specified"); - return false; - } - - uint32_t count; - if (!JS::ToUint32(cx, args.get(0), &count)) - return false; - - HelperThreadState().waitForAllThreads(); - js::oom::targetThread = targetThread; - OOM_maxAllocations = OOM_counter + count; - OOM_failAlways = false; - return true; + return SetupOOMFailure(cx, false, argc, vp); } static bool @@ -1065,6 +1043,7 @@ ResetOOMFailure(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); args.rval().setBoolean(OOM_counter >= OOM_maxAllocations); + js::oom::targetThread = js::oom::THREAD_TYPE_NONE; OOM_maxAllocations = UINT32_MAX; return true; } From c0902ce3afc02767c104b964667d89421389f3aa Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Tue, 6 Oct 2015 14:50:50 +0100 Subject: [PATCH 027/228] Bug 1209911 - Enable threads for existing OOM tests r=terrence --HG-- extra : rebase_source : fd0d010b3daa26f9d3d17741dc1f0058e0b46901 --- js/src/jit-test/tests/gc/bug-1165966.js | 2 +- js/src/jit-test/tests/gc/bug-1171909.js | 1 - js/src/jit-test/tests/gc/bug-1208994.js | 2 -- js/src/jit-test/tests/gc/oomInDebugger.js | 2 -- js/src/jit-test/tests/gc/oomInExceptionHandlerBailout.js | 2 -- js/src/jit-test/tests/gc/oomInFormatStackDump.js | 2 -- js/src/jit-test/tests/gc/oomInNewGlobal.js | 2 -- js/src/jit-test/tests/gc/oomInParseFunction.js | 2 -- js/src/jit-test/tests/gc/oomInWeakMap.js | 2 -- 9 files changed, 1 insertion(+), 16 deletions(-) diff --git a/js/src/jit-test/tests/gc/bug-1165966.js b/js/src/jit-test/tests/gc/bug-1165966.js index 24464e68343a..62c5b1a37264 100644 --- a/js/src/jit-test/tests/gc/bug-1165966.js +++ b/js/src/jit-test/tests/gc/bug-1165966.js @@ -1,4 +1,4 @@ -// |jit-test| --no-threads; --no-ion +// |jit-test| --no-ion load(libdir + 'oomTest.js'); var g = newGlobal(); oomTest(function() { diff --git a/js/src/jit-test/tests/gc/bug-1171909.js b/js/src/jit-test/tests/gc/bug-1171909.js index 01179fa052ad..5a210fe051bd 100644 --- a/js/src/jit-test/tests/gc/bug-1171909.js +++ b/js/src/jit-test/tests/gc/bug-1171909.js @@ -1,3 +1,2 @@ -// |jit-test| --no-threads; allow-unhandlable-oom load(libdir + 'oomTest.js'); oomTest((function(x) { assertEq(x + y + ex, 25); })); diff --git a/js/src/jit-test/tests/gc/bug-1208994.js b/js/src/jit-test/tests/gc/bug-1208994.js index 151ec909aee8..4c69e49879a5 100644 --- a/js/src/jit-test/tests/gc/bug-1208994.js +++ b/js/src/jit-test/tests/gc/bug-1208994.js @@ -1,4 +1,2 @@ -// |jit-test| --no-threads - load(libdir + 'oomTest.js'); oomTest(() => getBacktrace({args: oomTest[load+1], locals: true, thisprops: true})); diff --git a/js/src/jit-test/tests/gc/oomInDebugger.js b/js/src/jit-test/tests/gc/oomInDebugger.js index 39cae89bf28f..96f8174bcc81 100644 --- a/js/src/jit-test/tests/gc/oomInDebugger.js +++ b/js/src/jit-test/tests/gc/oomInDebugger.js @@ -1,5 +1,3 @@ -// |jit-test| --no-threads - load(libdir + 'oomTest.js'); var g = newGlobal(); oomTest(() => Debugger(g)); diff --git a/js/src/jit-test/tests/gc/oomInExceptionHandlerBailout.js b/js/src/jit-test/tests/gc/oomInExceptionHandlerBailout.js index 927b164e955d..c00950e77e66 100644 --- a/js/src/jit-test/tests/gc/oomInExceptionHandlerBailout.js +++ b/js/src/jit-test/tests/gc/oomInExceptionHandlerBailout.js @@ -1,5 +1,3 @@ -// |jit-test| --no-threads - load(libdir + 'oomTest.js'); oomTest(() => { diff --git a/js/src/jit-test/tests/gc/oomInFormatStackDump.js b/js/src/jit-test/tests/gc/oomInFormatStackDump.js index 4c2ea4feefaf..c801a91f67e9 100644 --- a/js/src/jit-test/tests/gc/oomInFormatStackDump.js +++ b/js/src/jit-test/tests/gc/oomInFormatStackDump.js @@ -1,4 +1,2 @@ -// |jit-test| --no-threads - load(libdir + 'oomTest.js'); oomTest(() => getBacktrace({args: true, locals: true, thisprops: true})); diff --git a/js/src/jit-test/tests/gc/oomInNewGlobal.js b/js/src/jit-test/tests/gc/oomInNewGlobal.js index b12d1d49ae62..e371c72021fb 100644 --- a/js/src/jit-test/tests/gc/oomInNewGlobal.js +++ b/js/src/jit-test/tests/gc/oomInNewGlobal.js @@ -1,4 +1,2 @@ -// |jit-test| --no-threads - load(libdir + 'oomTest.js'); oomTest(newGlobal); diff --git a/js/src/jit-test/tests/gc/oomInParseFunction.js b/js/src/jit-test/tests/gc/oomInParseFunction.js index e25eccb5ba48..070e0e710396 100644 --- a/js/src/jit-test/tests/gc/oomInParseFunction.js +++ b/js/src/jit-test/tests/gc/oomInParseFunction.js @@ -1,4 +1,2 @@ -// |jit-test| --no-threads - load(libdir + 'oomTest.js'); oomTest(() => eval("function f() {}")); diff --git a/js/src/jit-test/tests/gc/oomInWeakMap.js b/js/src/jit-test/tests/gc/oomInWeakMap.js index 2cc1fb8c5ab9..e26fb5d5f3ed 100644 --- a/js/src/jit-test/tests/gc/oomInWeakMap.js +++ b/js/src/jit-test/tests/gc/oomInWeakMap.js @@ -1,5 +1,3 @@ -// |jit-test| --no-threads - load(libdir + 'oomTest.js'); oomTest(function () { eval(`var wm = new WeakMap(); From 106d89e80bdf2524ef8defba7d24fab6debeb12c Mon Sep 17 00:00:00 2001 From: "Dustin J. Mitchell" Date: Fri, 2 Oct 2015 11:37:28 -0400 Subject: [PATCH 028/228] Bug 1209494: remove refs to RELENGAPI_TOKEN, TOOLTOOL_CACHE; r=jlund RELENGAPI_TOKEN is no longer needed, with the advent of the relengapi proxy. TOOLTOOL_CACHE has a reasonable default (and why would you want to change that, anyway?) --HG-- extra : commitid : 9Gn9KVVehsc extra : rebase_source : edb6e3ec5a14baeab8146d890595cafcacdb4d03 --- testing/taskcluster/scripts/builder/build-linux.sh | 13 ------------- testing/taskcluster/tasks/builds/android_api_11.yml | 6 ------ .../tasks/builds/android_api_11_b2gdroid.yml | 6 ------ .../tasks/builds/android_api_11_partner_sample1.yml | 6 ------ 4 files changed, 31 deletions(-) diff --git a/testing/taskcluster/scripts/builder/build-linux.sh b/testing/taskcluster/scripts/builder/build-linux.sh index 7f3eda25b1ab..7a3171c2de52 100644 --- a/testing/taskcluster/scripts/builder/build-linux.sh +++ b/testing/taskcluster/scripts/builder/build-linux.sh @@ -15,8 +15,6 @@ echo "running as" $(id) : TOOLTOOL_CACHE ${TOOLTOOL_CACHE:=/home/worker/tooltool-cache} -: RELENGAPI_TOKEN ${RELENGAPI_TOKEN+HIDDEN} - : NEED_XVFB ${NEED_XVFB:=false} : MH_CUSTOM_BUILD_VARIANT_CFG ${MH_CUSTOM_BUILD_VARIANT_CFG} @@ -100,17 +98,6 @@ if [ "$CHECKOUT_GAIA" = true ]; then ln -s $gaia_dir $GECKO_DIR/gaia fi -set +x -# mozharness scripts look for the relengapi token at this location, so put it there, -# if specified -if [ -n "${RELENGAPI_TOKEN}" ]; then - echo 'Storing $RELENGAPI_TOKEN in /builds/relengapi.tok' - echo ${RELENGAPI_TOKEN} > /builds/relengapi.tok - # unset it so that mozharness doesn't "helpfully" log it - unset RELENGAPI_TOKEN -fi -set -x - # $TOOLTOOL_CACHE bypasses mozharness completely and is read by tooltool_wrapper.sh to set the # cache. However, only some mozharness scripts use tooltool_wrapper.sh, so this may not be # entirely effective. diff --git a/testing/taskcluster/tasks/builds/android_api_11.yml b/testing/taskcluster/tasks/builds/android_api_11.yml index 08974ea2ac33..2b1f8b85220b 100644 --- a/testing/taskcluster/tasks/builds/android_api_11.yml +++ b/testing/taskcluster/tasks/builds/android_api_11.yml @@ -41,12 +41,6 @@ task: MH_BRANCH: {{project}} MH_BUILD_POOL: taskcluster - # image paths - TOOLTOOL_CACHE: '/home/worker/tooltool-cache' - - # authentication - RELENGAPI_TOKEN: 'TODO' # 1164612: encrypt this secret - maxRunTime: 36000 command: ["/bin/bash", "bin/build.sh"] diff --git a/testing/taskcluster/tasks/builds/android_api_11_b2gdroid.yml b/testing/taskcluster/tasks/builds/android_api_11_b2gdroid.yml index 050d117676d1..3d4fdfb024c3 100644 --- a/testing/taskcluster/tasks/builds/android_api_11_b2gdroid.yml +++ b/testing/taskcluster/tasks/builds/android_api_11_b2gdroid.yml @@ -43,12 +43,6 @@ task: CHECKOUT_GAIA: true - # image paths - TOOLTOOL_CACHE: '/home/worker/tooltool-cache' - - # authentication - RELENGAPI_TOKEN: 'TODO' # 1164612: encrypt this secret - maxRunTime: 36000 command: ["/bin/bash", "bin/build.sh"] diff --git a/testing/taskcluster/tasks/builds/android_api_11_partner_sample1.yml b/testing/taskcluster/tasks/builds/android_api_11_partner_sample1.yml index 18e99d5b5cd6..f79c5249ed25 100644 --- a/testing/taskcluster/tasks/builds/android_api_11_partner_sample1.yml +++ b/testing/taskcluster/tasks/builds/android_api_11_partner_sample1.yml @@ -52,12 +52,6 @@ task: PARTNER_HEAD_REV: 756f0378d4cac87e5e6c405249ede5effe082da2 PARTNER_DEST_DIR: '/home/worker/workspace/build/partner' - # image paths - TOOLTOOL_CACHE: '/home/worker/tooltool-cache' - - # authentication - RELENGAPI_TOKEN: 'TODO' # 1164612: encrypt this secret - maxRunTime: 36000 command: ["/bin/bash", "bin/build.sh"] From c49ce9299fbd3a725c41000812a4d022faa7ac02 Mon Sep 17 00:00:00 2001 From: Andrew Halberstadt Date: Tue, 29 Sep 2015 09:03:39 -0400 Subject: [PATCH 029/228] Bug 1209628 - Package mozharness alongside other build artifacts instead of 'package-tests', r=gps Mozharness isn't part of the test package, so shouldn't really be packaged during 'package-tests'. --HG-- extra : commitid : LIK7qJMSPHi extra : rebase_source : 644c8dd6e0e993b063709ba06e9634d52cb6596d --- testing/testsuite-targets.mk | 7 ------- toolkit/mozapps/installer/package-name.mk | 3 +++ toolkit/mozapps/installer/packager.mk | 6 +++++- toolkit/mozapps/installer/upload-files.mk | 1 + 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/testing/testsuite-targets.mk b/testing/testsuite-targets.mk index b9ad724cd79f..c7f2adf0a075 100644 --- a/testing/testsuite-targets.mk +++ b/testing/testsuite-targets.mk @@ -422,12 +422,6 @@ package-tests-prepare-dest: @rm -f '$(DIST)/$(PKG_PATH)$(TEST_PACKAGE)' $(NSINSTALL) -D $(DIST)/$(PKG_PATH) -package-tests-mozharness: package-tests-prepare-dest - $(call py_action,test_archive, \ - mozharness \ - $(abspath $(DIST))/$(PKG_PATH)/mozharness.zip) -package-tests: package-tests-mozharness - define package_archive package-tests-$(1): stage-all package-tests-prepare-dest $$(call py_action,test_archive, \ @@ -565,7 +559,6 @@ stage-instrumentation-tests: make-stage-dir jstestbrowser \ package-tests \ package-tests-prepare-dest \ - package-tests-mozharness \ package-tests-common \ make-stage-dir \ stage-all \ diff --git a/toolkit/mozapps/installer/package-name.mk b/toolkit/mozapps/installer/package-name.mk index 72014cf2376e..5c5f486d94ce 100644 --- a/toolkit/mozapps/installer/package-name.mk +++ b/toolkit/mozapps/installer/package-name.mk @@ -132,6 +132,9 @@ SYMBOL_ARCHIVE_BASENAME = $(PKG_BASENAME).crashreporter-symbols # Code coverage package naming CODE_COVERAGE_ARCHIVE_BASENAME = $(PKG_BASENAME).code-coverage-gcno +# Mozharness naming +MOZHARNESS_PACKAGE = mozharness.zip + # Test package naming TEST_PACKAGE = $(PKG_BASENAME).common.tests.zip CPP_TEST_PACKAGE = $(PKG_BASENAME).cppunittest.tests.zip diff --git a/toolkit/mozapps/installer/packager.mk b/toolkit/mozapps/installer/packager.mk index 49b8d97acdc4..1e80689706e4 100644 --- a/toolkit/mozapps/installer/packager.mk +++ b/toolkit/mozapps/installer/packager.mk @@ -54,9 +54,13 @@ stage-package: $(MOZ_PKG_MANIFEST) $(MOZ_PKG_MANIFEST_DEPS) $(MOZ_PKG_MANIFEST) $(DIST) $(DIST)/$(STAGEPATH)$(MOZ_PKG_DIR)$(if $(MOZ_PKG_MANIFEST),,$(_BINPATH)) \ $(if $(filter omni,$(MOZ_PACKAGER_FORMAT)),$(if $(NON_OMNIJAR_FILES),--non-resource $(NON_OMNIJAR_FILES))) $(PYTHON) $(MOZILLA_DIR)/toolkit/mozapps/installer/find-dupes.py $(DIST)/$(STAGEPATH)$(MOZ_PKG_DIR) + # Package mozharness + $(call py_action,test_archive, \ + mozharness \ + $(abspath $(DIST))/$(PKG_PATH)$(MOZHARNESS_PACKAGE)) ifndef LIBXUL_SDK ifdef MOZ_PACKAGE_JSSHELL -# Package JavaScript Shell + # Package JavaScript Shell @echo 'Packaging JavaScript Shell...' $(RM) $(PKG_JSSHELL) $(MAKE_JSSHELL) diff --git a/toolkit/mozapps/installer/upload-files.mk b/toolkit/mozapps/installer/upload-files.mk index 84652413d49c..822161112a79 100644 --- a/toolkit/mozapps/installer/upload-files.mk +++ b/toolkit/mozapps/installer/upload-files.mk @@ -733,6 +733,7 @@ UPLOAD_FILES= \ $(call QUOTED_WILDCARD,$(DIST)/$(COMPLETE_MAR)) \ $(call QUOTED_WILDCARD,$(DIST)/$(LANGPACK)) \ $(call QUOTED_WILDCARD,$(wildcard $(DIST)/$(PARTIAL_MAR))) \ + $(call QUOTED_WILDCARD,$(DIST)/$(PKG_PATH)$(MOZHARNESS_PACKAGE)) \ $(call QUOTED_WILDCARD,$(DIST)/$(PKG_PATH)$(TEST_PACKAGE)) \ $(call QUOTED_WILDCARD,$(DIST)/$(PKG_PATH)$(CPP_TEST_PACKAGE)) \ $(call QUOTED_WILDCARD,$(DIST)/$(PKG_PATH)$(XPC_TEST_PACKAGE)) \ From 93ed1d9a46d07ba6ff2309814d09dbdb7c80f0b0 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Sat, 12 Sep 2015 17:38:51 -0400 Subject: [PATCH 030/228] Bug 1204269 - Use the worker private in order to determine the origin of the entry settings object for workers; r=smaug --- dom/base/WebSocket.cpp | 44 ++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/dom/base/WebSocket.cpp b/dom/base/WebSocket.cpp index 6a44ec5394c7..220038d7dd72 100644 --- a/dom/base/WebSocket.cpp +++ b/dom/base/WebSocket.cpp @@ -1546,26 +1546,32 @@ WebSocketImpl::Init(JSContext* aCx, !Preferences::GetBool("network.websocket.allowInsecureFromHTTPS", false)) { // Confirmed we are opening plain ws:// and want to prevent this from a - // secure context (e.g. https). Check the principal's uri to determine if - // we were loaded from https. - nsCOMPtr globalObject(GetEntryGlobal()); - if (globalObject) { - nsCOMPtr principal(globalObject->PrincipalOrNull()); - if (principal) { - nsCOMPtr uri; - principal->GetURI(getter_AddRefs(uri)); - if (uri) { - bool originIsHttps = false; - aRv = uri->SchemeIs("https", &originIsHttps); - if (NS_WARN_IF(aRv.Failed())) { - return; - } + // secure context (e.g. https). + nsCOMPtr principal; + nsCOMPtr originURI; + if (mWorkerPrivate) { + // For workers, retrieve the URI from the WorkerPrivate + principal = mWorkerPrivate->GetPrincipal(); + } else { + // Check the principal's uri to determine if we were loaded from https. + nsCOMPtr globalObject(GetEntryGlobal()); + if (globalObject) { + principal = globalObject->PrincipalOrNull(); + } + } - if (originIsHttps) { - aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); - return; - } - } + if (principal) { + principal->GetURI(getter_AddRefs(originURI)); + } + if (originURI) { + bool originIsHttps = false; + aRv = originURI->SchemeIs("https", &originIsHttps); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + if (originIsHttps) { + aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); + return; } } } From a2917e316f57ca4dd815b1e07aa0c1a5adaf320a Mon Sep 17 00:00:00 2001 From: Eric Faust Date: Mon, 5 Oct 2015 13:24:02 -0700 Subject: [PATCH 031/228] Bug 1211546 - Unbreak the non-unified build. (r=sfink, r=nbp, r=shu) --- js/src/gc/Barrier.cpp | 98 +++++++++++++++++++++------------------- js/src/jsobjinlines.h | 1 + js/src/vm/CodeCoverage.h | 2 +- 3 files changed, 54 insertions(+), 47 deletions(-) diff --git a/js/src/gc/Barrier.cpp b/js/src/gc/Barrier.cpp index 8c96726e3634..df42dfaf9802 100644 --- a/js/src/gc/Barrier.cpp +++ b/js/src/gc/Barrier.cpp @@ -13,27 +13,31 @@ #include "js/HashTable.h" #include "js/Value.h" #include "vm/ScopeObject.h" +#include "vm/SharedArrayObject.h" +#include "vm/SharedTypedArrayObject.h" #include "vm/Symbol.h" +namespace js { + #ifdef DEBUG template void -js::BarrieredBase::assertTypeConstraints() const +BarrieredBase::assertTypeConstraints() const { - static_assert(mozilla::IsBaseOf::Type>::value || + static_assert(mozilla::IsBaseOf::Type>::value || mozilla::IsSame::value || mozilla::IsSame::value || - mozilla::IsSame::value, + mozilla::IsSame::value, "ensure only supported types are instantiated with barriers"); } #define INSTANTIATE_ALL_VALID_TYPES(type) \ - template void js::BarrieredBase::assertTypeConstraints() const; + template void BarrieredBase::assertTypeConstraints() const; FOR_EACH_GC_POINTER_TYPE(INSTANTIATE_ALL_VALID_TYPES) #undef INSTANTIATE_ALL_VALID_TYPES bool -js::HeapSlot::preconditionForSet(NativeObject* owner, Kind kind, uint32_t slot) +HeapSlot::preconditionForSet(NativeObject* owner, Kind kind, uint32_t slot) { return kind == Slot ? &owner->getSlotRef(slot) == this @@ -41,7 +45,7 @@ js::HeapSlot::preconditionForSet(NativeObject* owner, Kind kind, uint32_t slot) } bool -js::HeapSlot::preconditionForWriteBarrierPost(NativeObject* obj, Kind kind, uint32_t slot, +HeapSlot::preconditionForWriteBarrierPost(NativeObject* obj, Kind kind, uint32_t slot, Value target) const { return kind == Slot @@ -50,33 +54,33 @@ js::HeapSlot::preconditionForWriteBarrierPost(NativeObject* obj, Kind kind, uint } bool -js::RuntimeFromMainThreadIsHeapMajorCollecting(JS::shadow::Zone* shadowZone) +RuntimeFromMainThreadIsHeapMajorCollecting(JS::shadow::Zone* shadowZone) { return shadowZone->runtimeFromMainThread()->isHeapMajorCollecting(); } bool -js::CurrentThreadIsIonCompiling() +CurrentThreadIsIonCompiling() { return TlsPerThreadData.get()->ionCompiling; } bool -js::CurrentThreadIsIonCompilingSafeForMinorGC() +CurrentThreadIsIonCompilingSafeForMinorGC() { return TlsPerThreadData.get()->ionCompilingSafeForMinorGC; } bool -js::CurrentThreadIsGCSweeping() +CurrentThreadIsGCSweeping() { - return js::TlsPerThreadData.get()->gcSweeping; + return TlsPerThreadData.get()->gcSweeping; } bool -js::CurrentThreadIsHandlingInitFailure() +CurrentThreadIsHandlingInitFailure() { - JSRuntime* rt = js::TlsPerThreadData.get()->runtimeIfOnOwnerThread(); + JSRuntime* rt = TlsPerThreadData.get()->runtimeIfOnOwnerThread(); return rt && rt->handlingInitFailure; } @@ -85,44 +89,30 @@ js::CurrentThreadIsHandlingInitFailure() template template void -js::ReadBarrierFunctor::operator()(T* t) +ReadBarrierFunctor::operator()(T* t) { InternalGCMethods::readBarrier(t); } -template void js::ReadBarrierFunctor::operator()(JS::Symbol*); -template void js::ReadBarrierFunctor::operator()(JSObject*); -template void js::ReadBarrierFunctor::operator()(JSString*); +template void ReadBarrierFunctor::operator()(JS::Symbol*); +template void ReadBarrierFunctor::operator()(JSObject*); +template void ReadBarrierFunctor::operator()(JSString*); template template void -js::PreBarrierFunctor::operator()(T* t) +PreBarrierFunctor::operator()(T* t) { InternalGCMethods::preBarrier(t); } -template void js::PreBarrierFunctor::operator()(JS::Symbol*); -template void js::PreBarrierFunctor::operator()(JSObject*); -template void js::PreBarrierFunctor::operator()(JSString*); -template void js::PreBarrierFunctor::operator()(JS::Symbol*); -template void js::PreBarrierFunctor::operator()(JSString*); - -JS_PUBLIC_API(void) -JS::HeapObjectPostBarrier(JSObject** objp, JSObject* prev, JSObject* next) -{ - MOZ_ASSERT(objp); - js::InternalGCMethods::postBarrier(objp, prev, next); -} - -JS_PUBLIC_API(void) -JS::HeapValuePostBarrier(JS::Value* valuep, const Value& prev, const Value& next) -{ - MOZ_ASSERT(valuep); - js::InternalGCMethods::postBarrier(valuep, prev, next); -} +template void PreBarrierFunctor::operator()(JS::Symbol*); +template void PreBarrierFunctor::operator()(JSObject*); +template void PreBarrierFunctor::operator()(JSString*); +template void PreBarrierFunctor::operator()(JS::Symbol*); +template void PreBarrierFunctor::operator()(JSString*); template -/* static */ js::HashNumber -js::MovableCellHasher::hash(const Lookup& l) +/* static */ HashNumber +MovableCellHasher::hash(const Lookup& l) { if (!l) return 0; @@ -134,15 +124,15 @@ js::MovableCellHasher::hash(const Lookup& l) MOZ_ASSERT(CurrentThreadCanAccessZone(l->zoneFromAnyThread()) || l->zoneFromAnyThread()->isSelfHostingZone()); - js::HashNumber hn; + HashNumber hn; if (!l->zoneFromAnyThread()->getHashCode(l, &hn)) - js::CrashAtUnhandlableOOM("failed to get a stable hash code"); + CrashAtUnhandlableOOM("failed to get a stable hash code"); return hn; } template /* static */ bool -js::MovableCellHasher::match(const Key& k, const Lookup& l) +MovableCellHasher::match(const Key& k, const Lookup& l) { // Return true if both are null or false if only one is null. if (!k) @@ -168,7 +158,23 @@ js::MovableCellHasher::match(const Key& k, const Lookup& l) return uidK == uidL; } -template struct js::MovableCellHasher; -template struct js::MovableCellHasher; -template struct js::MovableCellHasher; -template struct js::MovableCellHasher; +template struct MovableCellHasher; +template struct MovableCellHasher; +template struct MovableCellHasher; +template struct MovableCellHasher; + +} // namespace js + +JS_PUBLIC_API(void) +JS::HeapObjectPostBarrier(JSObject** objp, JSObject* prev, JSObject* next) +{ + MOZ_ASSERT(objp); + js::InternalGCMethods::postBarrier(objp, prev, next); +} + +JS_PUBLIC_API(void) +JS::HeapValuePostBarrier(JS::Value* valuep, const Value& prev, const Value& next) +{ + MOZ_ASSERT(valuep); + js::InternalGCMethods::postBarrier(valuep, prev, next); +} diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 9067a2bca019..87a3d91edd08 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -29,6 +29,7 @@ #include "jscompartmentinlines.h" #include "jsgcinlines.h" +#include "jit/AtomicOperations-inl.h" #include "vm/TypeInference-inl.h" namespace js { diff --git a/js/src/vm/CodeCoverage.h b/js/src/vm/CodeCoverage.h index 7bf4e89717df..9dc2237afa98 100644 --- a/js/src/vm/CodeCoverage.h +++ b/js/src/vm/CodeCoverage.h @@ -110,7 +110,7 @@ class LCovCompartment LCovSource* lookupOrAdd(JSCompartment* comp, JSObject* sso); private: - typedef Vector> LCovSourceVector; + typedef mozilla::Vector> LCovSourceVector; // LifoAlloc backend for all temporary allocations needed to stash the // strings to be written in the file. From d6db05aa780d7980f685e9e810ecdb96f0d45c5e Mon Sep 17 00:00:00 2001 From: Till Schneidereit Date: Mon, 5 Oct 2015 13:24:03 -0700 Subject: [PATCH 032/228] Bug 1185106 - Part 1: ShellPromise boilerplate. (r=efaust) --- js/src/Makefile.in | 1 + js/src/builtin/Promise.cpp | 97 ++++++++++++++++++++++++++++++++++++++ js/src/builtin/Promise.h | 25 ++++++++++ js/src/builtin/Promise.js | 27 +++++++++++ js/src/jsprototypes.h | 7 +++ js/src/moz.build | 1 + js/src/vm/GlobalObject.cpp | 5 ++ js/src/vm/GlobalObject.h | 6 +++ 8 files changed, 169 insertions(+) create mode 100644 js/src/builtin/Promise.cpp create mode 100644 js/src/builtin/Promise.h create mode 100644 js/src/builtin/Promise.js diff --git a/js/src/Makefile.in b/js/src/Makefile.in index 04ca77dc5eb1..7c5156ffbed4 100644 --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -294,6 +294,7 @@ selfhosting_srcs := \ $(srcdir)/builtin/Module.js \ $(srcdir)/builtin/Number.js \ $(srcdir)/builtin/Object.js \ + $(srcdir)/builtin/Promise.js \ $(srcdir)/builtin/Reflect.js \ $(srcdir)/builtin/RegExp.js \ $(srcdir)/builtin/String.js \ diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp new file mode 100644 index 000000000000..ce3b58cdd032 --- /dev/null +++ b/js/src/builtin/Promise.cpp @@ -0,0 +1,97 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * 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/. */ + +#include "builtin/Promise.h" + +#include "jscntxt.h" + +#include "jsobjinlines.h" + +using namespace js; + +static const JSFunctionSpec promise_methods[] = { + JS_SELF_HOSTED_FN("catch", "Promise_catch", 1, 0), + JS_SELF_HOSTED_FN("then", "Promise_then", 2, 0), + JS_FS_END +}; + +static const JSFunctionSpec promise_static_methods[] = { + JS_SELF_HOSTED_FN("all", "Promise_all", 1, 0), + JS_SELF_HOSTED_FN("race", "Promise_race", 1, 0), + JS_SELF_HOSTED_FN("reject", "Promise_reject", 1, 0), + JS_SELF_HOSTED_FN("resolve", "Promise_resolve", 1, 0), + JS_FS_END +}; + +static bool +PromiseConstructor(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + + JSObject* obj = NewBuiltinClassInstance(cx, &ShellPromiseObject::class_); + if (!obj) + return false; + // TODO: store the resolve and reject callbacks. + args.rval().setObject(*obj); + return true; +} + +static JSObject* +CreatePromisePrototype(JSContext* cx, JSProtoKey key) +{ + return cx->global()->createBlankPrototype(cx, &ShellPromiseObject::protoClass_); +} + +const Class ShellPromiseObject::class_ = { + "ShellPromise", + JSCLASS_HAS_CACHED_PROTO(JSProto_ShellPromise), + nullptr, /* addProperty */ + nullptr, /* delProperty */ + nullptr, /* getProperty */ + nullptr, /* setProperty */ + nullptr, /* enumerate */ + nullptr, /* resolve */ + nullptr, /* mayResolve */ + nullptr, /* finalize */ + nullptr, /* call */ + nullptr, /* hasInstance */ + nullptr, /* construct */ + nullptr, /* trace */ + { + GenericCreateConstructor, + CreatePromisePrototype, + promise_static_methods, + nullptr, + promise_methods + } +}; + +const Class ShellPromiseObject::protoClass_ = { + "ShellPromise", + JSCLASS_HAS_CACHED_PROTO(JSProto_ShellPromise), + nullptr, /* addProperty */ + nullptr, /* delProperty */ + nullptr, /* getProperty */ + nullptr, /* setProperty */ + nullptr, /* enumerate */ + nullptr, /* resolve */ + nullptr, /* mayResolve */ + nullptr, /* finalize */ + nullptr, /* call */ + nullptr, /* hasInstance */ + nullptr, /* construct */ + nullptr, /* trace */ + { + DELEGATED_CLASSSPEC(&ShellPromiseObject::class_.spec), + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + ClassSpec::IsDelegated + } +}; diff --git a/js/src/builtin/Promise.h b/js/src/builtin/Promise.h new file mode 100644 index 000000000000..52f9d934155b --- /dev/null +++ b/js/src/builtin/Promise.h @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * 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/. */ + +#ifndef builtin_Promise_h +#define builtin_Promise_h + +#include "vm/NativeObject.h" + +namespace js { + +class AutoSetNewObjectMetadata; + +class ShellPromiseObject : public NativeObject +{ + public: + static const Class class_; + static const Class protoClass_; +}; + +} // namespace js + +#endif /* builtin_Promise_h */ diff --git a/js/src/builtin/Promise.js b/js/src/builtin/Promise.js new file mode 100644 index 000000000000..03b408ee4496 --- /dev/null +++ b/js/src/builtin/Promise.js @@ -0,0 +1,27 @@ +/* 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/. */ + +function Promise_all(iterable) { + global.print("Hi, I'm Promise_all. Please implement me."); +} + +function Promise_race(iterable) { + global.print("Hi, I'm Promise_race. Please implement me."); +} + +function Promise_reject(iterable) { + global.print("Hi, I'm Promise_reject. Please implement me."); +} + +function Promise_resolve(iterable) { + global.print("Hi, I'm Promise_resolve. Please implement me."); +} + +function Promise_catch(onRejected) { + global.print("Hi, I'm Promise_catch. Please implement me."); +} + +function Promise_then(onFulfilled, onRejected) { + global.print("Hi, I'm Promise_then. Please implement me."); +} diff --git a/js/src/jsprototypes.h b/js/src/jsprototypes.h index e9e413ebef10..c3eac76ae0d6 100644 --- a/js/src/jsprototypes.h +++ b/js/src/jsprototypes.h @@ -56,6 +56,12 @@ #define IF_SAB(real,imaginary) imaginary #endif +#ifdef NIGHTLY_BUILD +#define IF_NIGHTLY(real,imaginary) real +#else +#define IF_NIGHTLY(real,imaginary) imaginary +#endif + #define JS_FOR_PROTOTYPES(real,imaginary) \ imaginary(Null, 0, InitNullClass, dummy) \ real(Object, 1, InitViaClassSpec, OCLASP(Plain)) \ @@ -115,6 +121,7 @@ IF_SAB(real,imaginary)(Atomics, 53, InitAtomicsClass, OCLASP real(Module, 55, InitModuleClass, OCLASP(Module)) \ real(ImportEntry, 56, InitImportEntryClass, OCLASP(ImportEntry)) \ real(ExportEntry, 57, InitExportEntryClass, OCLASP(ExportEntry)) \ +IF_NIGHTLY(real, imaginary)(ShellPromise, 58, InitViaClassSpec, OCLASP(ShellPromise)) \ #define JS_FOR_EACH_PROTOTYPE(macro) JS_FOR_PROTOTYPES(macro,macro) diff --git a/js/src/moz.build b/js/src/moz.build index cf811a13d080..779794bb06ac 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -152,6 +152,7 @@ UNIFIED_SOURCES += [ 'builtin/ModuleObject.cpp', 'builtin/Object.cpp', 'builtin/Profilers.cpp', + 'builtin/Promise.cpp', 'builtin/Reflect.cpp', 'builtin/ReflectParse.cpp', 'builtin/SIMD.cpp', diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index cce3fcd68127..f56aaf083713 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -23,6 +23,11 @@ #include "builtin/MapObject.h" #include "builtin/ModuleObject.h" #include "builtin/Object.h" + +#ifdef NIGHTLY_BUILD +#include "builtin/Promise.h" +#endif + #include "builtin/RegExp.h" #include "builtin/SIMD.h" #include "builtin/SymbolObject.h" diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index 68a9e621ebe4..6b31fbaa8497 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -382,6 +382,12 @@ class GlobalObject : public NativeObject return &global->getPrototype(JSProto_Symbol).toObject().as(); } + static NativeObject* getOrCreatePromisePrototype(JSContext* cx, Handle global) { + if (!ensureConstructor(cx, global, JSProto_ShellPromise)) + return nullptr; + return &global->getPrototype(JSProto_ShellPromise).toObject().as(); + } + static NativeObject* getOrCreateRegExpPrototype(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_RegExp)) return nullptr; From b0c9ef4c118b372c8831e9e11bc617666ed7d0c5 Mon Sep 17 00:00:00 2001 From: Mariusz Kierski Date: Mon, 5 Oct 2015 13:24:03 -0700 Subject: [PATCH 033/228] Bug 1185106 - Part 2: Implement ShellPromise. (r=till) --- js/src/builtin/Promise.cpp | 56 +++++- js/src/builtin/Promise.h | 4 + js/src/builtin/Promise.js | 234 +++++++++++++++++++++++- js/src/builtin/SelfHostingDefines.h | 9 + js/src/js.msg | 5 + js/src/shell/js.cpp | 71 +++++++ js/src/tests/ecma_6/Promise/promise.js | 45 +++++ js/src/tests/ecma_6/Promise/security.js | 12 ++ js/src/tests/ecma_6/Promise/shell.js | 23 +++ js/src/vm/SelfHosting.cpp | 68 +++++++ js/src/vm/Xdr.h | 4 +- 11 files changed, 513 insertions(+), 18 deletions(-) create mode 100644 js/src/tests/ecma_6/Promise/promise.js create mode 100644 js/src/tests/ecma_6/Promise/security.js create mode 100644 js/src/tests/ecma_6/Promise/shell.js diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp index ce3b58cdd032..cf3f25fc3424 100644 --- a/js/src/builtin/Promise.cpp +++ b/js/src/builtin/Promise.cpp @@ -8,6 +8,8 @@ #include "jscntxt.h" +#include "builtin/SelfHostingDefines.h" + #include "jsobjinlines.h" using namespace js; @@ -26,19 +28,61 @@ static const JSFunctionSpec promise_static_methods[] = { JS_FS_END }; -static bool +namespace js { + +bool PromiseConstructor(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); - JSObject* obj = NewBuiltinClassInstance(cx, &ShellPromiseObject::class_); - if (!obj) + if (args.length() == 0) { + JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED, + "ShellPromise.constructor", "0", "s"); return false; - // TODO: store the resolve and reject callbacks. - args.rval().setObject(*obj); + } + + HandleValue fn = args.get(0); + + if (!IsCallable(fn)) { + JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_CALLABLE, + "Argument 1 of ShellPromise.constructor"); + return false; + } + + RootedObject promise(cx, NewBuiltinClassInstance(cx, &ShellPromiseObject::class_)); + if (!promise) + return false; + + JS_SetReservedSlot(promise, PROMISE_STATE_SLOT, NumberValue(PROMISE_STATE_PENDING)); + JS_SetReservedSlot(promise, PROMISE_VALUE_SLOT, NullValue()); + JS_SetReservedSlot(promise, PROMISE_DEFERREDS_SLOT, NullValue()); + + RootedValue initRval(cx); + JS::AutoValueVector argValues(cx); + argValues.append(ObjectValue(*promise)); + argValues.append(fn); + HandleValueArray arr(argValues); + + JSAtom* promiseInitAtom; + if (!(promiseInitAtom = Atomize(cx, "Promise_init", 12))) + return false; + + RootedPropertyName name(cx, promiseInitAtom->asPropertyName()); + RootedValue selfHostedFun(cx); + + if (!GlobalObject::getIntrinsicValue(cx, cx->global(), name, &selfHostedFun)) + return false; + + if (!JS_CallFunctionValue(cx, promise, selfHostedFun, arr, &initRval)) + return false; + + args.rval().setObject(*promise); + return true; } +} + static JSObject* CreatePromisePrototype(JSContext* cx, JSProtoKey key) { @@ -47,7 +91,7 @@ CreatePromisePrototype(JSContext* cx, JSProtoKey key) const Class ShellPromiseObject::class_ = { "ShellPromise", - JSCLASS_HAS_CACHED_PROTO(JSProto_ShellPromise), + JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_ShellPromise), nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ diff --git a/js/src/builtin/Promise.h b/js/src/builtin/Promise.h index 52f9d934155b..53f1399416da 100644 --- a/js/src/builtin/Promise.h +++ b/js/src/builtin/Promise.h @@ -16,10 +16,14 @@ class AutoSetNewObjectMetadata; class ShellPromiseObject : public NativeObject { public: + static const unsigned RESERVED_SLOTS = 3; static const Class class_; static const Class protoClass_; }; +bool +PromiseConstructor(JSContext* cx, unsigned argc, Value* vp); + } // namespace js #endif /* builtin_Promise_h */ diff --git a/js/src/builtin/Promise.js b/js/src/builtin/Promise.js index 03b408ee4496..65fc9dd1295a 100644 --- a/js/src/builtin/Promise.js +++ b/js/src/builtin/Promise.js @@ -2,26 +2,240 @@ * 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/. */ -function Promise_all(iterable) { - global.print("Hi, I'm Promise_all. Please implement me."); +/** + * This implementation is by no means complete and is using a polyfill. + * In particular, it doesn't fully comply to ES6 Promises spec. + * The list of incompatibilities may not be complete and includes: + * + * - no [Symbol.species] implementation + * - implementation is not really async at all, but all is executed + * in correct order + * - Promise.race is not implemented (not necessary for async/await) + * - Promise.all implementation currently only handles arrays, no other + * iterables. + */ + + /** + * This polyfill implements the Promise specification in the following way: + * At first, Promise is initialized with the intrinsic Promise constructor, + * with its initialization completed by calling Promise_init. The goal is to + * completely resolve/reject the promise. There are certain helper functions: + * - resolveOneStep() executes "one step" of the promise - which means + * getting either the final value or next promise towards complete execution. + * - resolveCompletely() executes the entire promise, which merely means + * resolving one step at a time, until the final step no longer resolves + * to a promise (which means either resolving to a value or rejecting). + * + * Once resolution is finished, resolveCompletely() is called in order to + * update state of the promise. It also spawns callbacks that may have been + * deferred with a then() - they are NOT normally taken into consideration, + * because resolveCompletely() just runs one path. + */ + +/** + * Below is a simple simulation of an event loop. Events enqueued using + * this setTimeout implementation must be manually triggered by calling + * runEvents(). + */ +var eventQueue = new List(); + +function runEvents() { + while (eventQueue.length > 0) { + var evt = callFunction(std_Array_pop, eventQueue); + evt(); + } } -function Promise_race(iterable) { - global.print("Hi, I'm Promise_race. Please implement me."); +function setTimeout(cb, interval) { + if (!IsCallable(cb)) + ThrowTypeError(JSMSG_NOT_CALLABLE, "Argument 0"); + if (interval !== 0) + ThrowTypeError(JSMSG_SETTIMEOUT_INTERVAL_NONZERO); + callFunction(std_Array_push, eventQueue, cb); } -function Promise_reject(iterable) { - global.print("Hi, I'm Promise_reject. Please implement me."); +function Handler(onFulfilled, onRejected, resolve, reject) { + this.onFulfilled = IsCallable(onFulfilled) ? onFulfilled : null; + this.onRejected = IsCallable(onRejected) ? onRejected : null; + this.resolve = resolve; + this.reject = reject; } -function Promise_resolve(iterable) { - global.print("Hi, I'm Promise_resolve. Please implement me."); +MakeConstructible(Handler, std_Object_create(null)); + +function Promise_setState(promise, state) { + UnsafeSetReservedSlot(promise, PROMISE_STATE_SLOT, state); +} + +function Promise_getState(promise) { + return UnsafeGetReservedSlot(promise, PROMISE_STATE_SLOT); +} + +function Promise_setDeferreds(promise, deferreds) { + UnsafeSetReservedSlot(promise, PROMISE_DEFERREDS_SLOT, deferreds); +} + +function Promise_getDeferreds(promise) { + return UnsafeGetReservedSlot(promise, PROMISE_DEFERREDS_SLOT); +} + +function Promise_setValue(promise, value) { + UnsafeSetReservedSlot(promise, PROMISE_VALUE_SLOT, value); +} + +function Promise_getValue(promise) { + return UnsafeGetReservedSlot(promise, PROMISE_VALUE_SLOT); +} + +function Promise_init(promise, fn) { + Promise_setDeferreds(promise, new List()); + resolveOneStep(fn, + function(value) { resolveCompletely(promise, value); }, + function(reason) { reject(promise, reason); }); +} + +function Promise_isThenable(valueOrPromise) { + if (valueOrPromise && (typeof valueOrPromise === 'object' || IsCallable(valueOrPromise))) { + var then = valueOrPromise.then; + if (IsCallable(then)) + return true; + } + return false; +} + +function Promise_all(promises) { + var length = promises.length; + var results = []; + return NewPromise(function (resolve, reject) { + if (length === 0) + return resolve([]); + var remaining = length; + function resolveChain(index, valueOrPromise) { + try { + if (Promise_isThenable(valueOrPromise)) { + callFunction(valueOrPromise.then, valueOrPromise, + function (valueOrPromise) { resolveChain(index, valueOrPromise); }, + reject); + } else { + _DefineDataProperty(results, index, valueOrPromise); + if (--remaining === 0) + resolve(results); + } + } catch (ex) { + reject(ex); + } + } + for (var i = 0; i < length; i++) + resolveChain(i, promises[i]); + }); +} + +function Promise_race(values) { + ThrowTypeError(JSMSG_NOT_IMPLEMENTED, "Promise.race"); +} + +function Promise_reject(value) { + return NewPromise(function (resolve, reject) { + reject(value); + }); +} + +function Promise_resolve(value) { + if (value && typeof value === 'object' && IsPromise(value)) + return value; + + return NewPromise(function (resolve) { + resolve(value); + }); } function Promise_catch(onRejected) { - global.print("Hi, I'm Promise_catch. Please implement me."); + return callFunction(Promise_then, this, undefined, onRejected); +} + +function asap(cb) { + setTimeout(cb, 0); +} + +function deferOrExecute(promise, deferred) { + if (Promise_getState(promise) === PROMISE_STATE_PENDING) { + Promise_getDeferreds(promise).push(deferred); + return; + } + + asap(function() { + var cb = Promise_getState(promise) === PROMISE_STATE_RESOLVED ? + deferred.onFulfilled : deferred.onRejected; + if (cb === null) { + var value = Promise_getValue(promise); + (Promise_getState(promise) === PROMISE_STATE_RESOLVED ? deferred.resolve : deferred.reject)(value); + return; + } + var returnValue; + try { + returnValue = cb(Promise_getValue(promise)); + } catch (e) { + deferred.reject(e); + return; + } + deferred.resolve(returnValue); + }); +} + +function resolveOneStep(fn, onFulfilled, onRejected) { + var done = false; + var callOnce = function(cb) { + return function(value) { + if (done) return; + done = true; + cb(value); + }; + }; + + try { + fn(callOnce(onFulfilled), callOnce(onRejected)); + } catch (ex) { + callOnce(onRejected)(ex); + } +} + +function resolveCompletely(promise, valueOrPromise) { + try { + // FIXME this is probably not a type error + if (valueOrPromise === promise) + ThrowTypeError(JSMSG_PROMISE_RESOLVED_WITH_ITSELF); + + if (Promise_isThenable(valueOrPromise)) { + resolveOneStep(function(resolve, reject) { valueOrPromise.then(resolve, reject); }, + function(value) { resolveCompletely(promise, value); }, + function(value) { reject(promise, value); }); + } + else + callFunction(resolvingFinished, promise, PROMISE_STATE_RESOLVED, valueOrPromise); + } catch (ex) { + callFunction(reject, promise, ex); + } +} + +function reject(promise, reason) { + callFunction(resolvingFinished, promise, PROMISE_STATE_REJECTED, reason); +} + +function resolvingFinished(state, newValue) { + Promise_setState(this, state); + Promise_setValue(this, newValue); + var deferreds = Promise_getDeferreds(this); + for (var i = 0, len = deferreds.length; i < len; i++) + deferOrExecute(this, deferreds[i]); + Promise_setDeferreds(this, null); } function Promise_then(onFulfilled, onRejected) { - global.print("Hi, I'm Promise_then. Please implement me."); + var promise = this; + var newPromise = NewPromise(function(resolve, reject) { + deferOrExecute(promise, + new Handler(onFulfilled, onRejected, resolve, reject)); + }); + runEvents(); + return newPromise; } diff --git a/js/src/builtin/SelfHostingDefines.h b/js/src/builtin/SelfHostingDefines.h index e11fc82a39a8..290319d92364 100644 --- a/js/src/builtin/SelfHostingDefines.h +++ b/js/src/builtin/SelfHostingDefines.h @@ -33,6 +33,15 @@ // Stores the private WeakMap slot used for WeakSets #define WEAKSET_MAP_SLOT 0 +// Slots for use with promises implementation. +#define PROMISE_STATE_SLOT 0 +#define PROMISE_VALUE_SLOT 1 +#define PROMISE_DEFERREDS_SLOT 2 + +#define PROMISE_STATE_PENDING 0 +#define PROMISE_STATE_RESOLVED 1 +#define PROMISE_STATE_REJECTED 2 + #define ITERATOR_SLOT_TARGET 0 // Used for collection iterators. #define ITERATOR_SLOT_RANGE 1 diff --git a/js/src/js.msg b/js/src/js.msg index b7f41bd6a8fd..e4d744e4dc34 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -106,6 +106,7 @@ MSG_DEF(JSMSG_TERMINATED, 1, JSEXN_ERR, "Script terminated by timeo MSG_DEF(JSMSG_PROTO_NOT_OBJORNULL, 1, JSEXN_TYPEERR, "{0}.prototype is not an object or null") MSG_DEF(JSMSG_CANT_CALL_CLASS_CONSTRUCTOR, 0, JSEXN_TYPEERR, "class constructors must be invoked with |new|") MSG_DEF(JSMSG_DISABLED_DERIVED_CLASS, 1, JSEXN_INTERNALERR, "{0} temporarily disallowed in derived class constructors") +MSG_DEF(JSMSG_NOT_CALLABLE, 1, JSEXN_TYPEERR, "{0} is not callable") // JSON MSG_DEF(JSMSG_JSON_BAD_PARSE, 3, JSEXN_SYNTAXERR, "JSON.parse: {0} at line {1} column {2} of the JSON data") @@ -508,6 +509,10 @@ MSG_DEF(JSMSG_NO_INDEXED_SETTER, 2, JSEXN_TYPEERR, "{0} doesn't have an // Super MSG_DEF(JSMSG_CANT_DELETE_SUPER, 0, JSEXN_REFERENCEERR, "invalid delete involving 'super'") +// Promise +MSG_DEF(JSMSG_PROMISE_RESOLVED_WITH_ITSELF, 0, JSEXN_TYPEERR, "A promise cannot be resolved with itself") +MSG_DEF(JSMSG_SETTIMEOUT_INTERVAL_NONZERO, 0, JSEXN_TYPEERR, "Intervals other than 0 are not supported") + // Modules MSG_DEF(JSMSG_BAD_DEFAULT_EXPORT, 0, JSEXN_SYNTAXERR, "default export cannot be provided by export *") MSG_DEF(JSMSG_MISSING_INDIRECT_EXPORT, 0, JSEXN_SYNTAXERR, "indirect export not found") diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 4897f29003bb..2000b727125c 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -1536,6 +1536,68 @@ PrintErr(JSContext* cx, unsigned argc, Value* vp) return PrintInternal(cx, args, gErrFile); } +static bool +SetTimeout(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + + if (args.length() < 2) { + JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED, + "setTimeout", args.length() == 0 ? "0" : "1", "s"); + return false; + } + + RootedValue rval(cx); + JS::AutoValueVector argValues(cx); + argValues.append(args.get(0)); + argValues.append(args.get(1)); + HandleValueArray arr(argValues); + + JSAtom* setTimeoutAtom; + if (!(setTimeoutAtom = Atomize(cx, "setTimeout", 10))) + return false; + + RootedPropertyName name(cx, setTimeoutAtom->asPropertyName()); + RootedValue selfHostedFun(cx); + + if (!GlobalObject::getIntrinsicValue(cx, cx->global(), name, &selfHostedFun)) + return false; + + RootedObject undef(cx); + if (!JS_CallFunctionValue(cx, undef, selfHostedFun, arr, &rval)) + return false; + + args.rval().set(rval); + return true; +} + +static bool +RunEvents(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + + RootedValue rval(cx); + JS::AutoValueVector argValues(cx); + HandleValueArray arr(argValues); + + JSAtom* runEvents; + if (!(runEvents = Atomize(cx, "runEvents", 9))) + return false; + + RootedPropertyName name(cx, runEvents->asPropertyName()); + RootedValue selfHostedFun(cx); + + if (!GlobalObject::getIntrinsicValue(cx, cx->global(), name, &selfHostedFun)) + return false; + + RootedObject undef(cx); + if (!JS_CallFunctionValue(cx, undef, selfHostedFun, arr, &rval)) + return false; + + args.rval().set(rval); + return true; +} + static bool Help(JSContext* cx, unsigned argc, Value* vp); @@ -4596,6 +4658,15 @@ static const JSFunctionSpecWithHelp shell_functions[] = { "dateNow()", " Return the current time with sub-ms precision."), + JS_FN_HELP("setTimeout", SetTimeout, 2, 2, +"setTimeout(fn, timeout)", +" Execute a function after a specified timeout. Currently only 0 is supported."), + + JS_FN_HELP("runEvents", RunEvents, 2, 2, +"runEvents()", +" Run events that were scheduled using setTimeout() calls.\n" +" This call is required, because there is no real event loop."), + JS_FN_HELP("help", Help, 0, 0, "help([name ...])", " Display usage and help messages."), diff --git a/js/src/tests/ecma_6/Promise/promise.js b/js/src/tests/ecma_6/Promise/promise.js new file mode 100644 index 000000000000..0698604cd9f9 --- /dev/null +++ b/js/src/tests/ecma_6/Promise/promise.js @@ -0,0 +1,45 @@ +/** + * Because there is no way to "wait" for a callback in this testing system, + * there was a need to make one big promise out of all test cases. + */ + +var Promise = ShellPromise; + +Promise.all([ + + assertEventuallyEq(new Promise(resolve => resolve(2)), 2), + + assertEventuallyThrows(new Promise((_, reject) => reject(new Error())), Error), + + assertEventuallyThrows(new Promise(() => { throw new Error(); }), Error), + + assertEventuallyEq(new Promise(resolve => resolve()) + .then(() => 3), 3), + + assertEventuallyEq(new Promise(resolve => resolve()) + .then(() => new Promise(r => r(3))), 3), + + assertEventuallyEq(new Promise((_, reject) => reject(new Error())) + .catch(() => new Promise(r => r(3))), 3), + + assertEventuallyThrows(new Promise(resolve => resolve()) + .then(() => { throw new Error(); }), Error), + + assertEventuallyEq(new Promise((_, reject) => reject(new Error())) + .catch(() => 4), 4), + + assertEventuallyEq(Promise.resolve(5), 5), + + assertEventuallyThrows(Promise.reject(new Error()), Error), + + assertEventuallyDeepEq(Promise.all([]), []), + + assertEventuallyDeepEq(Promise.all(Array(10).fill() + .map((_, id) => new Promise(resolve => resolve(id)))), + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), + +]) + .then(() => { + if (typeof reportCompare === "function") + reportCompare(true, true); + }); diff --git a/js/src/tests/ecma_6/Promise/security.js b/js/src/tests/ecma_6/Promise/security.js new file mode 100644 index 000000000000..6971e3976430 --- /dev/null +++ b/js/src/tests/ecma_6/Promise/security.js @@ -0,0 +1,12 @@ +var Promise = ShellPromise; + +var oldThen = Promise.prototype.then; + +// Changing then() should not break catch() +Promise.prototype.then = function() { throw new Error(); }; + +new Promise(a => { throw new Error(); }) + .catch(() => { + if (typeof reportCompare === "function") + reportCompare(true, true); + }); diff --git a/js/src/tests/ecma_6/Promise/shell.js b/js/src/tests/ecma_6/Promise/shell.js new file mode 100644 index 000000000000..c15a30f2ac7e --- /dev/null +++ b/js/src/tests/ecma_6/Promise/shell.js @@ -0,0 +1,23 @@ +/** + * These functions are inspired by chai-as-promised library for promise testing + * in JS applications. They check if promises eventually resolve to a given value + * or are rejected with a specified error type. + */ + +if (typeof assertEventuallyEq === 'undefined') { + assertEventuallyEq = function(promise, expected) { + return promise.then(actual => assertEq(actual, expected)); + }; +} + +if (typeof assertEventuallyThrows === 'undefined') { + assertEventuallyThrows = function(promise, expectedErrorType) { + return promise.catch(actualE => assertEq(actualE instanceof expectedErrorType, true)); + }; +} + +if (typeof assertEventuallyDeepEq === 'undefined') { + assertEventuallyDeepEq = function(promise, expected) { + return promise.then(actual => assertDeepEq(actual, expected)); + }; +} diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 147131081b5d..9aaa6498d209 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -23,6 +23,7 @@ #include "builtin/MapObject.h" #include "builtin/ModuleObject.h" #include "builtin/Object.h" +#include "builtin/Promise.h" #include "builtin/Reflect.h" #include "builtin/SelfHostingDefines.h" #include "builtin/SIMD.h" @@ -441,6 +442,54 @@ intrinsic_GetIteratorPrototype(JSContext* cx, unsigned argc, Value* vp) return true; } +static bool +intrinsic_NewPromise(JSContext* cx, unsigned argc, Value* vp) +{ + return js::PromiseConstructor(cx, argc, vp); +} + +static bool +intrinsic_IsPromise(JSContext* cx, unsigned argc, Value* vp) { + CallArgs args = CallArgsFromVp(argc, vp); + MOZ_ASSERT(args.length() == 1); + MOZ_ASSERT(args[0].isObject()); + bool isPromise = args[0].toObject().getClass() == &ShellPromiseObject::class_; + + args.rval().setBoolean(isPromise); + return true; +} + +static bool +intrinsic_SetFunName(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + MOZ_ASSERT(args.length() == 2); + MOZ_ASSERT(args[0].isObject() && args[0].toObject().is()); + MOZ_ASSERT(args[1].isString()); + JSAtom* atom = AtomizeString(cx, args[1].toString()); + if (atom == nullptr) + return false; + RootedFunction fun(cx, &args[0].toObject().as()); + fun->setFlags(fun->flags() & ~JSFunction::HAS_GUESSED_ATOM); + fun->initAtom(atom); + + return true; +} + +static bool +intrinsic_GetFunName(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + MOZ_ASSERT(args.length() == 1); + MOZ_ASSERT(args[0].isObject() && args[0].toObject().is()); + PropertyName* name = args[0].toObject().as().name(); + if (!name) + args.rval().setUndefined(); + else + args.rval().setString(name); + return true; +} + static bool intrinsic_NewArrayIterator(JSContext* cx, unsigned argc, Value* vp) { @@ -1194,6 +1243,20 @@ intrinsic_IsWeakSet(JSContext* cx, unsigned argc, Value* vp) return true; } +bool +intrinsic_SetFunctionExtendedSlot(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + MOZ_ASSERT(args.length() == 3); + MOZ_ASSERT(args[0].isObject()); + MOZ_ASSERT(args[0].toObject().is()); + MOZ_ASSERT(args[1].isInt32()); + + args[0].toObject().as().setExtendedSlot(args[1].toPrivateUint32(), args[2]); + args.rval().setUndefined(); + return true; +} + /** * Returns the default locale as a well-formed, but not necessarily canonicalized, * BCP-47 language tag. @@ -1433,6 +1496,7 @@ static const JSFunctionSpec intrinsic_functions[] = { JS_FN("_ConstructorForTypedArray", intrinsic_ConstructorForTypedArray, 1,0), JS_FN("DecompileArg", intrinsic_DecompileArg, 2,0), JS_FN("RuntimeDefaultLocale", intrinsic_RuntimeDefaultLocale, 0,0), + JS_FN("SetFunctionExtendedSlot", intrinsic_SetFunctionExtendedSlot, 3,0), JS_FN("LocalTZA", intrinsic_LocalTZA, 0,0), JS_INLINABLE_FN("_IsConstructing", intrinsic_IsConstructing, 0,0, @@ -1520,7 +1584,11 @@ static const JSFunctionSpec intrinsic_functions[] = { CallNonGenericSelfhostedMethod>, 2, 0), JS_FN("IsWeakSet", intrinsic_IsWeakSet, 1,0), + JS_FN("NewPromise", intrinsic_NewPromise, 1,0), + JS_FN("IsPromise", intrinsic_IsPromise, 1,0), + JS_FN("SetFunName", intrinsic_SetFunName, 2,0), + JS_FN("GetFunName", intrinsic_GetFunName, 1,0), // See builtin/TypedObject.h for descriptors of the typedobj functions. JS_FN("NewOpaqueTypedObject", js::NewOpaqueTypedObject, 1, 0), JS_FN("NewDerivedTypedObject", js::NewDerivedTypedObject, 3, 0), diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h index e65fc7cb8b13..f39cf4e8a162 100644 --- a/js/src/vm/Xdr.h +++ b/js/src/vm/Xdr.h @@ -29,11 +29,11 @@ namespace js { * * https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode */ -static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 310; +static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 311; static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND); -static_assert(JSErr_Limit == 415, +static_assert(JSErr_Limit == 418, "GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or " "removed MSG_DEFs from js.msg, you should increment " "XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's " From 5932f613caf5fd26801fbda641330b2be44173eb Mon Sep 17 00:00:00 2001 From: Mariusz Kierski Date: Mon, 5 Oct 2015 13:24:03 -0700 Subject: [PATCH 034/228] Bug 1185106 - Part 3: Add parser support for Async functions. (r=efaust) --- js/src/asmjs/AsmJSValidate.cpp | 2 +- js/src/builtin/ReflectParse.cpp | 45 +++- js/src/frontend/BytecodeCompiler.cpp | 6 +- js/src/frontend/BytecodeEmitter.cpp | 8 + js/src/frontend/FoldConstants.cpp | 2 + js/src/frontend/FullParseHandler.h | 5 + js/src/frontend/NameFunctions.cpp | 1 + js/src/frontend/ParseNode.cpp | 6 +- js/src/frontend/ParseNode.h | 1 + js/src/frontend/Parser.cpp | 223 +++++++++++++++---- js/src/frontend/Parser.h | 39 ++-- js/src/frontend/SharedContext.h | 7 +- js/src/frontend/SyntaxParseHandler.h | 3 +- js/src/frontend/TokenKind.h | 2 + js/src/frontend/TokenStream.cpp | 5 + js/src/frontend/TokenStream.h | 10 + js/src/js.msg | 7 + js/src/jsfun.cpp | 7 +- js/src/jsfun.h | 13 ++ js/src/jsscript.cpp | 2 + js/src/jsscript.h | 18 +- js/src/tests/ecma_7/AsyncFunctions/shell.js | 0 js/src/tests/ecma_7/AsyncFunctions/syntax.js | 85 +++++++ js/src/vm/CommonPropertyNames.h | 2 + js/src/vm/Keywords.h | 1 + js/src/vm/Xdr.h | 2 +- 26 files changed, 427 insertions(+), 75 deletions(-) create mode 100644 js/src/tests/ecma_7/AsyncFunctions/shell.js create mode 100644 js/src/tests/ecma_7/AsyncFunctions/syntax.js diff --git a/js/src/asmjs/AsmJSValidate.cpp b/js/src/asmjs/AsmJSValidate.cpp index 55ffa08cbe20..cffd4f4e1a12 100644 --- a/js/src/asmjs/AsmJSValidate.cpp +++ b/js/src/asmjs/AsmJSValidate.cpp @@ -6348,7 +6348,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut) AsmJSParseContext* outerpc = m.parser().pc; Directives directives(outerpc); - FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, outerpc, directives, NotGenerator); + FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, outerpc, directives, NotGenerator, SyncFunction); if (!funbox) return false; diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp index 8c30db7c3996..82da131a8414 100644 --- a/js/src/builtin/ReflectParse.cpp +++ b/js/src/builtin/ReflectParse.cpp @@ -91,6 +91,7 @@ enum UnaryOperator { UNOP_BITNOT, UNOP_TYPEOF, UNOP_VOID, + UNOP_AWAIT, UNOP_LIMIT }; @@ -160,7 +161,8 @@ static const char* const unopNames[] = { "!", /* UNOP_NOT */ "~", /* UNOP_BITNOT */ "typeof", /* UNOP_TYPEOF */ - "void" /* UNOP_VOID */ + "void", /* UNOP_VOID */ + "await" /* UNOP_AWAIT */ }; static const char* const nodeTypeNames[] = { @@ -560,6 +562,29 @@ class NodeBuilder setResult(node, dst); } + bool newNode(ASTType type, TokenPos* pos, + const char* childName1, HandleValue child1, + const char* childName2, HandleValue child2, + const char* childName3, HandleValue child3, + const char* childName4, HandleValue child4, + const char* childName5, HandleValue child5, + const char* childName6, HandleValue child6, + const char* childName7, HandleValue child7, + const char* childName8, HandleValue child8, + MutableHandleValue dst) { + RootedObject node(cx); + return newNode(type, pos, &node) && + setProperty(node, childName1, child1) && + setProperty(node, childName2, child2) && + setProperty(node, childName3, child3) && + setProperty(node, childName4, child4) && + setProperty(node, childName5, child5) && + setProperty(node, childName6, child6) && + setProperty(node, childName7, child7) && + setProperty(node, childName8, child8) && + setResult(node, dst); + } + bool listNode(ASTType type, const char* propName, NodeVector& elts, TokenPos* pos, MutableHandleValue dst) { RootedValue array(cx); @@ -620,8 +645,8 @@ class NodeBuilder bool function(ASTType type, TokenPos* pos, HandleValue id, NodeVector& args, NodeVector& defaults, - HandleValue body, HandleValue rest, bool isGenerator, bool isExpression, - MutableHandleValue dst); + HandleValue body, HandleValue rest, bool isGenerator, bool isAsync, + bool isExpression, MutableHandleValue dst); bool variableDeclarator(HandleValue id, HandleValue init, TokenPos* pos, MutableHandleValue dst); @@ -1757,7 +1782,7 @@ bool NodeBuilder::function(ASTType type, TokenPos* pos, HandleValue id, NodeVector& args, NodeVector& defaults, HandleValue body, HandleValue rest, - bool isGenerator, bool isExpression, + bool isGenerator, bool isAsync, bool isExpression, MutableHandleValue dst) { RootedValue array(cx), defarray(cx); @@ -1767,6 +1792,7 @@ NodeBuilder::function(ASTType type, TokenPos* pos, return false; RootedValue isGeneratorVal(cx, BooleanValue(isGenerator)); + RootedValue isAsyncVal(cx, BooleanValue(isAsync)); RootedValue isExpressionVal(cx, BooleanValue(isExpression)); RootedValue cb(cx, callbacks[type]); @@ -1781,6 +1807,7 @@ NodeBuilder::function(ASTType type, TokenPos* pos, "body", body, "rest", rest, "generator", isGeneratorVal, + "async", isAsyncVal, "expression", isExpressionVal, dst); } @@ -2026,6 +2053,9 @@ ASTSerializer::unop(ParseNodeKind kind, JSOp op) if (kind == PNK_TYPEOFNAME || kind == PNK_TYPEOFEXPR) return UNOP_TYPEOF; + if (kind == PNK_AWAIT) + return UNOP_AWAIT; + switch (op) { case JSOP_NEG: return UNOP_NEG; @@ -3084,7 +3114,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) return leftAssociate(pn, dst); case PNK_POW: - return rightAssociate(pn, dst); + return rightAssociate(pn, dst); case PNK_DELETENAME: case PNK_DELETEPROP: @@ -3096,6 +3126,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) case PNK_NOT: case PNK_BITNOT: case PNK_POS: + case PNK_AWAIT: case PNK_NEG: { MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos)); @@ -3565,7 +3596,7 @@ ASTSerializer::function(ParseNode* pn, ASTType type, MutableHandleValue dst) // FIXME: Provide more information (legacy generator vs star generator). bool isGenerator = pn->pn_funbox->isGenerator(); - + bool isAsync = pn->pn_funbox->isAsync(); bool isExpression = #if JS_HAS_EXPR_CLOSURES func->isExprBody(); @@ -3588,7 +3619,7 @@ ASTSerializer::function(ParseNode* pn, ASTType type, MutableHandleValue dst) rest.setNull(); return functionArgsAndBody(pn->pn_body, args, defaults, &body, &rest) && builder.function(type, &pn->pn_pos, id, args, defaults, body, - rest, isGenerator, isExpression, dst); + rest, isGenerator, isAsync, isExpression, dst); } bool diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index 0e56102dd93d..28f55574cdb4 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -314,7 +314,7 @@ BytecodeCompiler::saveCallerFun(HandleScript evalCaller, MOZ_ASSERT_IF(fun->strict(), options.strictOption); Directives directives(/* strict = */ options.strictOption); ObjectBox* funbox = parser->newFunctionBox(/* fn = */ nullptr, fun, &parseContext, - directives, fun->generatorKind()); + directives, fun->generatorKind(), fun->asyncKind()); if (!funbox) return false; @@ -705,7 +705,7 @@ BytecodeCompiler::compileFunctionBody(MutableHandleFunction fun, ParseNode* fn; do { Directives newDirectives = directives; - fn = parser->standaloneFunctionBody(fun, formals, generatorKind, directives, + fn = parser->standaloneFunctionBody(fun, formals, generatorKind, SyncFunction, directives, &newDirectives, enclosingStaticScope); if (!fn && !handleParseFailure(newDirectives)) return false; @@ -865,7 +865,7 @@ frontend::CompileLazyFunction(JSContext* cx, Handle lazy, const cha Rooted fun(cx, lazy->functionNonDelazifying()); MOZ_ASSERT(!lazy->isLegacyGenerator()); - ParseNode* pn = parser.standaloneLazyFunction(fun, lazy->strict(), lazy->generatorKind()); + ParseNode* pn = parser.standaloneLazyFunction(fun, lazy->strict(), lazy->generatorKind(), lazy->asyncKind()); if (!pn) return false; diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 825e5f4a0ed1..5dad148c7cc4 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -1991,6 +1991,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) case PNK_PREDECREMENT: case PNK_POSTDECREMENT: case PNK_THROW: + case PNK_AWAIT: MOZ_ASSERT(pn->isArity(PN_UNARY)); *answer = true; return true; @@ -8021,6 +8022,13 @@ BytecodeEmitter::emitTree(ParseNode* pn) return false; break; + // PNK_AWAIT handling is not yet implemented (in this part), + // so currently we just return "true" as a placeholder. + case PNK_AWAIT: + if (!emit1(JSOP_TRUE)) + return false; + break; + case PNK_POSHOLDER: MOZ_ASSERT_UNREACHABLE("Should never try to emit PNK_POSHOLDER"); diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp index 003ed0b58334..6e523efa7a18 100644 --- a/js/src/frontend/FoldConstants.cpp +++ b/js/src/frontend/FoldConstants.cpp @@ -329,6 +329,7 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result) case PNK_CONDITIONAL: case PNK_TYPEOFNAME: case PNK_TYPEOFEXPR: + case PNK_AWAIT: case PNK_VOID: case PNK_NOT: case PNK_BITNOT: @@ -1853,6 +1854,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser& parser, bo return Fold(cx, &pn->pn_left, parser, inGenexpLambda); case PNK_YIELD: + case PNK_AWAIT: MOZ_ASSERT(pn->isArity(PN_BINARY)); MOZ_ASSERT((pn->pn_right->isKind(PNK_NAME) && !pn->pn_right->isAssigned()) || (pn->pn_right->isKind(PNK_ASSIGN) && diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index db069cdfd490..11d52018b6a4 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -436,6 +436,11 @@ class FullParseHandler return new_(PNK_YIELD, op, pos, value, gen); } + ParseNode* newAwaitExpression(uint32_t begin, ParseNode* value, ParseNode* gen) { + TokenPos pos(begin, value ? value->pn_pos.end : begin + 1); + return new_(PNK_AWAIT, JSOP_YIELD, pos, value, gen); + } + ParseNode* newYieldStarExpression(uint32_t begin, ParseNode* value, ParseNode* gen) { TokenPos pos(begin, value->pn_pos.end); return new_(PNK_YIELD_STAR, JSOP_NOP, pos, value, gen); diff --git a/js/src/frontend/NameFunctions.cpp b/js/src/frontend/NameFunctions.cpp index 9c5fae0b0839..64d0c3acd53f 100644 --- a/js/src/frontend/NameFunctions.cpp +++ b/js/src/frontend/NameFunctions.cpp @@ -488,6 +488,7 @@ class NameResolver break; case PNK_YIELD: + case PNK_AWAIT: MOZ_ASSERT(cur->isArity(PN_BINARY)); if (cur->pn_left) { if (!resolve(cur->pn_left, prefix)) diff --git a/js/src/frontend/ParseNode.cpp b/js/src/frontend/ParseNode.cpp index 4ab4aeff20f0..a90c9daa0bc4 100644 --- a/js/src/frontend/ParseNode.cpp +++ b/js/src/frontend/ParseNode.cpp @@ -324,7 +324,8 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack) // variable, or an assignment of a PNK_GENERATOR node to the '.generator' // local, for a synthesized, prepended initial yield. Yum! case PNK_YIELD_STAR: - case PNK_YIELD: { + case PNK_YIELD: + case PNK_AWAIT: { MOZ_ASSERT(pn->isArity(PN_BINARY)); MOZ_ASSERT(pn->pn_right); MOZ_ASSERT(pn->pn_right->isKind(PNK_NAME) || @@ -701,7 +702,8 @@ Parser::cloneParseTree(ParseNode* opn) RootedFunction fun(context, opn->pn_funbox->function()); NULLCHECK(pn->pn_funbox = newFunctionBox(pn, fun, pc, Directives(/* strict = */ opn->pn_funbox->strict()), - opn->pn_funbox->generatorKind())); + opn->pn_funbox->generatorKind(), + opn->pn_funbox->asyncKind())); NULLCHECK(pn->pn_body = cloneParseTree(opn->pn_body)); pn->pn_scopecoord = opn->pn_scopecoord; pn->pn_dflags = opn->pn_dflags; diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index b54f8accf933..5d3e7f00ed14 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -183,6 +183,7 @@ class PackedScopeCoordinate F(VOID) \ F(NOT) \ F(BITNOT) \ + F(AWAIT) \ \ /* \ * Binary operators. \ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 38f18d367c78..0e61f90e5dce 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -645,7 +645,8 @@ Parser::newObjectBox(JSObject* obj) template FunctionBox::FunctionBox(ExclusiveContext* cx, ObjectBox* traceListHead, JSFunction* fun, JSObject* enclosingStaticScope, ParseContext* outerpc, - Directives directives, bool extraWarnings, GeneratorKind generatorKind) + Directives directives, bool extraWarnings, GeneratorKind generatorKind, + FunctionAsyncKind asyncKind) : ObjectBox(fun, traceListHead), SharedContext(cx, directives, extraWarnings), bindings(), @@ -664,7 +665,8 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, ObjectBox* traceListHead, JSFunct usesArguments(false), usesApply(false), usesThis(false), - funCxFlags() + funCxFlags(), + _asyncKind(asyncKind) { // Functions created at parse time may be set singleton after parsing and // baked into JIT code, so they must be allocated tenured. They are held by @@ -678,6 +680,7 @@ Parser::newFunctionBox(Node fn, JSFunction* fun, ParseContext* outerpc, Directives inheritedDirectives, GeneratorKind generatorKind, + FunctionAsyncKind asyncKind, JSObject* enclosingStaticScope) { MOZ_ASSERT_IF(outerpc, enclosingStaticScope == outerpc->innermostStaticScope()); @@ -693,7 +696,7 @@ Parser::newFunctionBox(Node fn, JSFunction* fun, FunctionBox* funbox = alloc.new_(context, traceListHead, fun, enclosingStaticScope, outerpc, inheritedDirectives, options().extraWarningsOption, - generatorKind); + generatorKind, asyncKind); if (!funbox) { ReportOutOfMemory(context); return nullptr; @@ -836,7 +839,9 @@ Parser::checkStrictBinding(PropertyName* name, Node pn) if (!pc->sc->needStrictChecks()) return true; - if (name == context->names().eval || name == context->names().arguments || IsKeyword(name)) { + if (name == context->names().eval || name == context->names().arguments || + (IsKeyword(name) && name != context->names().await)) + { JSAutoByteString bytes; if (!AtomToPrintableString(context, name, &bytes)) return false; @@ -866,7 +871,10 @@ Parser::standaloneModule(HandleModuleObject module) if (!modulepc.init(*this)) return null(); + bool awaitIsKeyword = tokenStream.getAwaitIsKeyword(); + tokenStream.setAwaitIsKeyword(true); ParseNode* pn = statements(YieldIsKeyword); + tokenStream.setAwaitIsKeyword(awaitIsKeyword); if (!pn) return null(); @@ -941,6 +949,7 @@ ParseNode* Parser::standaloneFunctionBody(HandleFunction fun, Handle formals, GeneratorKind generatorKind, + FunctionAsyncKind asyncKind, Directives inheritedDirectives, Directives* newDirectives, HandleObject enclosingStaticScope) @@ -957,7 +966,7 @@ Parser::standaloneFunctionBody(HandleFunction fun, fn->pn_body = argsbody; FunctionBox* funbox = newFunctionBox(fn, fun, inheritedDirectives, generatorKind, - enclosingStaticScope); + asyncKind, enclosingStaticScope); if (!funbox) return null(); funbox->length = fun->nargs() - fun->hasRest(); @@ -1406,7 +1415,8 @@ struct BindData template JSFunction* Parser::newFunction(HandleAtom atom, FunctionSyntaxKind kind, - GeneratorKind generatorKind, HandleObject proto) + GeneratorKind generatorKind, FunctionAsyncKind asyncKind, + HandleObject proto) { MOZ_ASSERT_IF(kind == Statement, atom != nullptr); @@ -1452,6 +1462,10 @@ Parser::newFunction(HandleAtom atom, FunctionSyntaxKind kind, : JSFunction::INTERPRETED_GENERATOR); } + // We store the async wrapper in a slot for later access. + if (asyncKind == AsyncFunction) + allocKind = gc::AllocKind::FUNCTION_EXTENDED; + fun = NewFunctionWithProto(context, nullptr, 0, flags, nullptr, atom, proto, allocKind, TenuredObject); if (!fun) @@ -1833,7 +1847,7 @@ Parser::bindDestructuringArg(BindData* data, template bool Parser::functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind, - Node funcpn, bool* hasRest) + FunctionAsyncKind asyncKind, Node funcpn, bool* hasRest) { FunctionBox* funbox = pc->sc->asFunctionBox(); @@ -2021,11 +2035,20 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn // before the first default argument. funbox->length = pc->numArgs() - 1; } - Node def_expr = assignExprWithoutYield(yieldHandling, JSMSG_YIELD_IN_DEFAULT); + bool awaitIsKeyword; + if (asyncKind == AsyncFunction) { + awaitIsKeyword = tokenStream.getAwaitIsKeyword(); + tokenStream.setAwaitIsKeyword(true); + } + Node def_expr = assignExprWithoutYieldAndAwait(yieldHandling, JSMSG_YIELD_IN_DEFAULT); + if (!def_expr) return false; if (!handler.setLastFunctionArgumentDefault(funcpn, def_expr)) return false; + if (asyncKind == AsyncFunction) { + tokenStream.setAwaitIsKeyword(awaitIsKeyword); + } } if (parenFreeArrow || IsSetterKind(kind)) @@ -2210,7 +2233,7 @@ Parser::checkFunctionDefinition(HandlePropertyName funName, RootedFunction fun(context, handler.nextLazyInnerFunction()); MOZ_ASSERT(!fun->isLegacyGenerator()); FunctionBox* funbox = newFunctionBox(pn, fun, pc, Directives(/* strict = */ false), - fun->generatorKind()); + fun->generatorKind(), fun->asyncKind()); if (!funbox) return false; @@ -2419,9 +2442,11 @@ template typename ParseHandler::Node Parser::functionDef(InHandling inHandling, YieldHandling yieldHandling, HandlePropertyName funName, FunctionSyntaxKind kind, - GeneratorKind generatorKind, InvokedPrediction invoked) + GeneratorKind generatorKind, FunctionAsyncKind asyncKind, + InvokedPrediction invoked) { MOZ_ASSERT_IF(kind == Statement, funName); + MOZ_ASSERT_IF(asyncKind == AsyncFunction, generatorKind == StarGenerator); /* Make a TOK_FUNCTION node. */ Node pn = handler.newFunctionDefinition(); @@ -2448,7 +2473,7 @@ Parser::functionDef(InHandling inHandling, YieldHandling yieldHand if (!proto) return null(); } - RootedFunction fun(context, newFunction(funName, kind, generatorKind, proto)); + RootedFunction fun(context, newFunction(funName, kind, generatorKind, asyncKind, proto)); if (!fun) return null(); @@ -2463,8 +2488,8 @@ Parser::functionDef(InHandling inHandling, YieldHandling yieldHand tokenStream.tell(&start); while (true) { - if (functionArgsAndBody(inHandling, pn, fun, kind, generatorKind, directives, - &newDirectives)) + if (functionArgsAndBody(inHandling, pn, fun, kind, generatorKind, asyncKind, + directives, &newDirectives)) { break; } @@ -2534,6 +2559,7 @@ Parser::finishFunctionDefinition(Node pn, FunctionBox* funbo if (pc->sc->strict()) lazy->setStrict(); lazy->setGeneratorKind(funbox->generatorKind()); + lazy->setAsyncKind(funbox->asyncKind()); if (funbox->usesArguments && funbox->usesApply && funbox->usesThis) lazy->setUsesArgumentsApplyAndThis(); if (funbox->isDerivedClassConstructor()) @@ -2551,13 +2577,14 @@ bool Parser::functionArgsAndBody(InHandling inHandling, ParseNode* pn, HandleFunction fun, FunctionSyntaxKind kind, GeneratorKind generatorKind, + FunctionAsyncKind asyncKind, Directives inheritedDirectives, Directives* newDirectives) { ParseContext* outerpc = pc; // Create box for fun->object early to protect against last-ditch GC. - FunctionBox* funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind); + FunctionBox* funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind, asyncKind); if (!funbox) return false; @@ -2656,13 +2683,14 @@ bool Parser::functionArgsAndBody(InHandling inHandling, Node pn, HandleFunction fun, FunctionSyntaxKind kind, GeneratorKind generatorKind, + FunctionAsyncKind asyncKind, Directives inheritedDirectives, Directives* newDirectives) { ParseContext* outerpc = pc; // Create box for fun->object early to protect against last-ditch GC. - FunctionBox* funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind); + FunctionBox* funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind, asyncKind); if (!funbox) return false; @@ -2678,7 +2706,6 @@ Parser::functionArgsAndBody(InHandling inHandling, Node pn, if (!leaveFunction(pn, outerpc, kind)) return false; - // This is a lazy function inner to another lazy function. Remember the // inner function so that if the outer function is eventually parsed we do // not need any further parsing or processing of the inner function. @@ -2707,7 +2734,8 @@ Parser::appendToCallSiteObj(Node callSiteObj) template <> ParseNode* Parser::standaloneLazyFunction(HandleFunction fun, bool strict, - GeneratorKind generatorKind) + GeneratorKind generatorKind, + FunctionAsyncKind asyncKind) { MOZ_ASSERT(checkOptionsCalled); @@ -2722,7 +2750,7 @@ Parser::standaloneLazyFunction(HandleFunction fun, bool strict RootedObject enclosing(context, fun->lazyScript()->enclosingScope()); Directives directives(/* strict = */ strict); - FunctionBox* funbox = newFunctionBox(pn, fun, directives, generatorKind, enclosing); + FunctionBox* funbox = newFunctionBox(pn, fun, directives, generatorKind, asyncKind, enclosing); if (!funbox) return null(); funbox->length = fun->nargs() - fun->hasRest(); @@ -2780,12 +2808,12 @@ Parser::functionArgsAndBodyGeneric(InHandling inHandling, // function without concern for conversion to strict mode, use of lazy // parsing and such. - bool hasRest; - if (!functionArguments(yieldHandling, kind, pn, &hasRest)) - return false; - FunctionBox* funbox = pc->sc->asFunctionBox(); + bool hasRest; + if (!functionArguments(yieldHandling, kind, funbox->asyncKind(), pn, &hasRest)) + return false; + fun->setArgCount(pc->numArgs()); if (hasRest) fun->setHasRest(); @@ -2829,9 +2857,12 @@ Parser::functionArgsAndBodyGeneric(InHandling inHandling, #endif } + bool beforeAwaitIsKeyword = tokenStream.getAwaitIsKeyword(); + tokenStream.setAwaitIsKeyword(funbox->isAsync()); Node body = functionBody(inHandling, yieldHandling, kind, bodyType); if (!body) return false; + tokenStream.setAwaitIsKeyword(beforeAwaitIsKeyword); if ((kind != Method && !IsConstructorKind(kind)) && fun->name() && !checkStrictBinding(fun->name(), pn)) @@ -2877,7 +2908,8 @@ Parser::checkYieldNameValidity() template typename ParseHandler::Node -Parser::functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling) +Parser::functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling, + FunctionAsyncKind asyncKind) { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION)); @@ -2888,6 +2920,10 @@ Parser::functionStmt(YieldHandling yieldHandling, DefaultHandling return null(); if (tt == TOK_MUL) { + if (asyncKind != SyncFunction) { + report(ParseError, false, null(), JSMSG_ASYNC_GENERATOR); + return null(); + } generatorKind = StarGenerator; if (!tokenStream.getToken(&tt)) return null(); @@ -2913,12 +2949,14 @@ Parser::functionStmt(YieldHandling yieldHandling, DefaultHandling !report(ParseStrictError, pc->sc->strict(), null(), JSMSG_STRICT_FUNCTION_STATEMENT)) return null(); - return functionDef(InAllowed, yieldHandling, name, Statement, generatorKind); + if (asyncKind == AsyncFunction) + generatorKind = StarGenerator; + return functionDef(InAllowed, yieldHandling, name, Statement, generatorKind, asyncKind); } template typename ParseHandler::Node -Parser::functionExpr(InvokedPrediction invoked) +Parser::functionExpr(InvokedPrediction invoked, FunctionAsyncKind asyncKind) { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION)); @@ -2928,6 +2966,10 @@ Parser::functionExpr(InvokedPrediction invoked) return null(); if (tt == TOK_MUL) { + if (asyncKind != SyncFunction) { + report(ParseError, false, null(), JSMSG_ASYNC_GENERATOR); + return null(); + } generatorKind = StarGenerator; if (!tokenStream.getToken(&tt)) return null(); @@ -2944,8 +2986,10 @@ Parser::functionExpr(InvokedPrediction invoked) tokenStream.ungetToken(); } + if (asyncKind == AsyncFunction) + generatorKind = StarGenerator; YieldHandling yieldHandling = generatorKind != NotGenerator ? YieldIsKeyword : YieldIsName; - return functionDef(InAllowed, yieldHandling, name, Expression, generatorKind, invoked); + return functionDef(InAllowed, yieldHandling, name, Expression, generatorKind, asyncKind, invoked); } /* @@ -4933,7 +4977,7 @@ Parser::exportDeclaration() } case TOK_FUNCTION: - kid = functionStmt(YieldIsKeyword, NameRequired); + kid = functionStmt(YieldIsKeyword, NameRequired, SyncFunction); if (!kid) return null(); @@ -4983,7 +5027,7 @@ Parser::exportDeclaration() ParseNode* binding = nullptr; switch (tt) { case TOK_FUNCTION: - kid = functionStmt(YieldIsKeyword, AllowDefaultName); + kid = functionStmt(YieldIsKeyword, AllowDefaultName, SyncFunction); if (!kid) return null(); break; @@ -5968,7 +6012,7 @@ Parser::returnStatement(YieldHandling yieldHandling) template typename ParseHandler::Node Parser::newYieldExpression(uint32_t begin, typename ParseHandler::Node expr, - bool isYieldStar) + bool isYieldStar, bool isAwait) { Node generator = newName(context->names().dotGenerator); if (!generator) @@ -5977,7 +6021,9 @@ Parser::newYieldExpression(uint32_t begin, typename ParseHandler:: return null(); if (isYieldStar) return handler.newYieldStarExpression(begin, expr, generator); - return handler.newYieldExpression(begin, expr, generator); + if (isAwait) + return handler.newAwaitExpression(begin, expr, generator); + return handler.newYieldExpression(begin, expr, generator, JSOP_YIELD); } template @@ -6430,6 +6476,7 @@ JSOpFromPropertyType(PropertyType propType) case PropertyType::Normal: case PropertyType::Method: case PropertyType::GeneratorMethod: + case PropertyType::AsyncMethod: case PropertyType::Constructor: case PropertyType::DerivedConstructor: return JSOP_INITPROP; @@ -6451,8 +6498,8 @@ FunctionSyntaxKindFromPropertyType(PropertyType propType) case PropertyType::SetterNoExpressionClosure: return SetterNoExpressionClosure; case PropertyType::Method: - return Method; case PropertyType::GeneratorMethod: + case PropertyType::AsyncMethod: return Method; case PropertyType::Constructor: return ClassConstructor; @@ -6466,7 +6513,15 @@ FunctionSyntaxKindFromPropertyType(PropertyType propType) static GeneratorKind GeneratorKindFromPropertyType(PropertyType propType) { - return propType == PropertyType::GeneratorMethod ? StarGenerator : NotGenerator; + return (propType == PropertyType::GeneratorMethod || + propType == PropertyType::AsyncMethod) + ? StarGenerator : NotGenerator; +} + +static FunctionAsyncKind +AsyncKindFromPropertyType(PropertyType propType) +{ + return propType == PropertyType::AsyncMethod ? AsyncFunction : SyncFunction; } template <> @@ -6580,6 +6635,7 @@ Parser::classDefinition(YieldHandling yieldHandling, if (propType != PropertyType::Getter && propType != PropertyType::Setter && propType != PropertyType::Method && propType != PropertyType::GeneratorMethod && + propType != PropertyType::AsyncMethod && propType != PropertyType::Constructor && propType != PropertyType::DerivedConstructor) { report(ParseError, false, null(), JSMSG_BAD_METHOD_DEF); @@ -6748,6 +6804,19 @@ Parser::statement(YieldHandling yieldHandling, bool canHaveDirecti case TOK_NAME: { TokenKind next; + TokenKind nextSameLine = TOK_EOF; + +#ifdef NIGHTLY_BUILD + if (tokenStream.currentName() == context->names().async) { + if (!tokenStream.peekTokenSameLine(&nextSameLine)) + return null(); + if (nextSameLine == TOK_FUNCTION) { + tokenStream.consumeKnownToken(TOK_FUNCTION); + return functionStmt(yieldHandling, NameRequired, AsyncFunction); + } + } +#endif + if (!tokenStream.peekToken(&next)) return null(); if (next == TOK_COLON) @@ -6822,7 +6891,7 @@ Parser::statement(YieldHandling yieldHandling, bool canHaveDirecti // HoistableDeclaration[?Yield] case TOK_FUNCTION: - return functionStmt(yieldHandling, NameRequired); + return functionStmt(yieldHandling, NameRequired, SyncFunction); // ClassDeclaration[?Yield] case TOK_CLASS: @@ -7136,6 +7205,20 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl bool endsExpr; if (tt == TOK_NAME) { + TokenKind nextSameLine = TOK_EOF; + +#ifdef NIGHTLY_BUILD + if (tokenStream.currentName() == context->names().async) { + if (!tokenStream.peekTokenSameLine(&nextSameLine)) + return null(); + + if (nextSameLine == TOK_FUNCTION) { + tokenStream.consumeKnownToken(TOK_FUNCTION); + return functionExpr(PredictUninvoked, AsyncFunction); + } + } +#endif + if (!tokenStream.nextTokenEndsExpr(&endsExpr)) return null(); if (endsExpr) @@ -7156,8 +7239,14 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl return stringLiteral(); } - if (tt == TOK_YIELD && yieldExpressionsSupported()) + if (tt == TOK_YIELD && yieldExpressionsSupported()) { + if (pc->isAsync()) { + report(ParseError, false, null(), JSMSG_YIELD_IN_ASYNC); + return null(); + } return yieldExpression(inHandling); + } + tokenStream.ungetToken(); @@ -7217,7 +7306,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl return null(); } - Node arrowFunc = functionDef(inHandling, yieldHandling, nullptr, Arrow, NotGenerator); + Node arrowFunc = functionDef(inHandling, yieldHandling, nullptr, Arrow, NotGenerator, SyncFunction); if (!arrowFunc) return null(); @@ -7479,6 +7568,25 @@ Parser::unaryExpr(YieldHandling yieldHandling, InvokedPrediction i return handler.newDelete(begin, expr); } + case TOK_AWAIT: + { + TokenKind nextSameLine = TOK_EOF; + +#ifdef NIGHTLY_BUILD + if (!tokenStream.peekTokenSameLine(&nextSameLine, TokenStream::Operand)) + return null(); + if (nextSameLine != TOK_EOL) { + Node kid = unaryExpr(yieldHandling); + if (!kid) + return null(); + return newYieldExpression(begin, kid, /* isYieldStar = */ false, /* isAwait = */ true); + } else { + report(ParseError, false, null(), JSMSG_LINE_BREAK_AFTER_AWAIT); + return null(); + } +#endif + } + default: { Node pn = memberExpr(yieldHandling, tt, /* allowCallSyntax = */ true, invoked); if (!pn) @@ -8056,13 +8164,13 @@ Parser::generatorComprehensionLambda(GeneratorKind comprehensionKi } RootedFunction fun(context, newFunction(/* atom = */ nullptr, Expression, - comprehensionKind, proto)); + comprehensionKind, SyncFunction, proto)); if (!fun) return null(); // Create box for fun->object early to root it. Directives directives(/* strict = */ outerpc->sc->strict()); - FunctionBox* genFunbox = newFunctionBox(genfn, fun, outerpc, directives, comprehensionKind); + FunctionBox* genFunbox = newFunctionBox(genfn, fun, outerpc, directives, comprehensionKind, SyncFunction); if (!genFunbox) return null(); @@ -8390,8 +8498,16 @@ Parser::generatorComprehension(uint32_t begin) template typename ParseHandler::Node -Parser::assignExprWithoutYield(YieldHandling yieldHandling, unsigned msg) +Parser::assignExprWithoutYieldAndAwait(YieldHandling yieldHandling, unsigned msg) { + TokenKind tt; + if (!tokenStream.peekToken(&tt, TokenStream::Operand)) + return null(); + + if (tt == TOK_AWAIT) { + report(ParseError, false, null(), JSMSG_AWAIT_IN_DEFAULT); + return null(); + } uint32_t startYieldOffset = pc->lastYieldOffset; Node res = assignExpr(InAllowed, yieldHandling); if (res && pc->lastYieldOffset != startYieldOffset) { @@ -8923,12 +9039,32 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, MOZ_ASSERT(ltok != TOK_RC); bool isGenerator = false; + bool isAsync = false; + if (ltok == TOK_MUL) { isGenerator = true; if (!tokenStream.getToken(<ok, TokenStream::KeywordIsName)) return null(); } + if (ltok == TOK_NAME && tokenStream.currentName() == context->names().async) { + TokenKind tt; + if (!tokenStream.getToken(&tt, TokenStream::KeywordIsName)) + return null(); + if (tt != TOK_LP && tt != TOK_COLON) { + isAsync = true; + ltok = tt; + } else { + tokenStream.ungetToken(); + tokenStream.addModifierException(TokenStream::NoneIsKeywordIsName); + } + } + + if (isAsync && isGenerator) { + report(ParseError, false, null(), JSMSG_ASYNC_GENERATOR); + return null(); + } + propAtom.set(nullptr); Node propName; switch (ltok) { @@ -8950,7 +9086,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, case TOK_NAME: { propAtom.set(tokenStream.currentName()); // Do not look for accessor syntax on generators - if (isGenerator || + if (isGenerator || isAsync || !(propAtom.get() == context->names().get || propAtom.get() == context->names().set)) { @@ -9067,7 +9203,8 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, if (tt == TOK_LP) { tokenStream.ungetToken(); - *propType = isGenerator ? PropertyType::GeneratorMethod : PropertyType::Method; + *propType = isGenerator ? PropertyType::GeneratorMethod : + (isAsync ? PropertyType::AsyncMethod : PropertyType::Method); return propName; } @@ -9214,7 +9351,8 @@ Parser::methodDefinition(YieldHandling yieldHandling, PropertyType { FunctionSyntaxKind kind = FunctionSyntaxKindFromPropertyType(propType); GeneratorKind generatorKind = GeneratorKindFromPropertyType(propType); - return functionDef(InAllowed, yieldHandling, funName, kind, generatorKind); + FunctionAsyncKind asyncKind = AsyncKindFromPropertyType(propType); + return functionDef(InAllowed, yieldHandling, funName, kind, generatorKind, asyncKind); } template @@ -9323,7 +9461,8 @@ Parser::primaryExpr(YieldHandling yieldHandling, TokenKind tt, case TOK_YIELD: if (!checkYieldNameValidity()) return null(); - // Fall through. + + // Fall through. case TOK_NAME: return identifierName(yieldHandling); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index b929ec50447e..6f49a0536dab 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -127,6 +127,8 @@ struct MOZ_STACK_CLASS ParseContext : public GenericParseContext bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; } bool isStarGenerator() const { return generatorKind() == StarGenerator; } + bool isAsync() const { return sc->isFunctionBox() && sc->asFunctionBox()->isAsync(); } + bool isArrowFunction() const { return sc->isFunctionBox() && sc->asFunctionBox()->function()->isArrow(); } @@ -363,6 +365,7 @@ enum class PropertyType { SetterNoExpressionClosure, Method, GeneratorMethod, + AsyncMethod, Constructor, DerivedConstructor }; @@ -504,22 +507,26 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter ObjectBox* newObjectBox(JSObject* obj); FunctionBox* newFunctionBox(Node fn, JSFunction* fun, ParseContext* outerpc, Directives directives, GeneratorKind generatorKind, + FunctionAsyncKind asyncKind, JSObject* enclosingStaticScope); // Use when the funbox is the outermost. FunctionBox* newFunctionBox(Node fn, HandleFunction fun, Directives directives, - GeneratorKind generatorKind, HandleObject enclosingStaticScope) + GeneratorKind generatorKind, + FunctionAsyncKind asyncKind, + HandleObject enclosingStaticScope) { return newFunctionBox(fn, fun, nullptr, directives, generatorKind, - enclosingStaticScope); + asyncKind, enclosingStaticScope); } // Use when the funbox should be linked to the outerpc's innermost scope. FunctionBox* newFunctionBox(Node fn, HandleFunction fun, ParseContext* outerpc, - Directives directives, GeneratorKind generatorKind) + Directives directives, GeneratorKind generatorKind, + FunctionAsyncKind asyncKind) { RootedObject enclosing(context, outerpc->innermostStaticScope()); - return newFunctionBox(fn, fun, outerpc, directives, generatorKind, enclosing); + return newFunctionBox(fn, fun, outerpc, directives, generatorKind, asyncKind, enclosing); } ModuleBox* newModuleBox(Node pn, HandleModuleObject module); @@ -529,7 +536,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter * a function expression). */ JSFunction* newFunction(HandleAtom atom, FunctionSyntaxKind kind, GeneratorKind generatorKind, - HandleObject proto); + FunctionAsyncKind asyncKind, HandleObject proto); bool generateBlockId(JSObject* staticScope, uint32_t* blockIdOut) { if (blockScopes.length() == StmtInfoPC::BlockIdLimit) { @@ -568,7 +575,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter TokenKind* ttp); inline Node newName(PropertyName* name); - inline Node newYieldExpression(uint32_t begin, Node expr, bool isYieldStar = false); + inline Node newYieldExpression(uint32_t begin, Node expr, bool isYieldStar = false, bool isAsync = false); inline bool abortIfSyntaxParser(); @@ -589,13 +596,14 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter // Parse a function, given only its body. Used for the Function and // Generator constructors. Node standaloneFunctionBody(HandleFunction fun, Handle formals, - GeneratorKind generatorKind, + GeneratorKind generatorKind, FunctionAsyncKind asyncKind, Directives inheritedDirectives, Directives* newDirectives, HandleObject enclosingStaticScope); // Parse a function, given only its arguments and body. Used for lazily // parsed functions. - Node standaloneLazyFunction(HandleFunction fun, bool strict, GeneratorKind generatorKind); + Node standaloneLazyFunction(HandleFunction fun, bool strict, GeneratorKind generatorKind, + FunctionAsyncKind asyncKind); /* * Parse a function body. Pass StatementListBody if the body is a list of @@ -647,8 +655,10 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter * Some parsers have two versions: an always-inlined version (with an 'i' * suffix) and a never-inlined version (with an 'n' suffix). */ - Node functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling); - Node functionExpr(InvokedPrediction invoked = PredictUninvoked); + Node functionStmt(YieldHandling yieldHandling, + DefaultHandling defaultHandling, FunctionAsyncKind asyncKind); + Node functionExpr(InvokedPrediction invoked = PredictUninvoked, + FunctionAsyncKind asyncKind = SyncFunction); Node statements(YieldHandling yieldHandling); Node blockStatement(YieldHandling yieldHandling); @@ -681,7 +691,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter InvokedPrediction invoked = PredictUninvoked); Node assignExpr(InHandling inHandling, YieldHandling yieldHandling, InvokedPrediction invoked = PredictUninvoked); - Node assignExprWithoutYield(YieldHandling yieldHandling, unsigned err); + Node assignExprWithoutYieldAndAwait(YieldHandling yieldHandling, unsigned err); Node yieldExpression(InHandling inHandling); Node condExpr1(InHandling inHandling, YieldHandling yieldHandling, InvokedPrediction invoked = PredictUninvoked); @@ -705,13 +715,13 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter * Additional JS parsers. */ bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind, - Node funcpn, bool* hasRest); + FunctionAsyncKind asyncKind, Node funcpn, bool* hasRest); Node functionDef(InHandling inHandling, YieldHandling uieldHandling, HandlePropertyName name, - FunctionSyntaxKind kind, GeneratorKind generatorKind, + FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, InvokedPrediction invoked = PredictUninvoked); bool functionArgsAndBody(InHandling inHandling, Node pn, HandleFunction fun, - FunctionSyntaxKind kind, GeneratorKind generatorKind, + FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, Directives inheritedDirectives, Directives* newDirectives); Node unaryOpExpr(YieldHandling yieldHandling, ParseNodeKind kind, JSOp op, uint32_t begin); @@ -822,6 +832,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter // Top-level entrypoint into destructuring pattern checking/name-analyzing. bool checkDestructuringPattern(BindData* data, Node pattern); + // Recursive methods for checking/name-analyzing subcomponents of a // destructuring pattern. The array/object methods *must* be passed arrays // or objects. The name method may be passed anything but will report an diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h index 7ccabafccfb2..82030ec10fb8 100644 --- a/js/src/frontend/SharedContext.h +++ b/js/src/frontend/SharedContext.h @@ -301,10 +301,13 @@ class FunctionBox : public ObjectBox, public SharedContext FunctionContextFlags funCxFlags; + FunctionAsyncKind _asyncKind; + template FunctionBox(ExclusiveContext* cx, ObjectBox* traceListHead, JSFunction* fun, JSObject* enclosingStaticScope, ParseContext* pc, - Directives directives, bool extraWarnings, GeneratorKind generatorKind); + Directives directives, bool extraWarnings, GeneratorKind generatorKind, + FunctionAsyncKind asyncKind); ObjectBox* toObjectBox() override { return this; } JSFunction* function() const { return &object->as(); } @@ -316,6 +319,8 @@ class FunctionBox : public ObjectBox, public SharedContext bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; } bool isStarGenerator() const { return generatorKind() == StarGenerator; } bool isArrow() const { return function()->isArrow(); } + bool isAsync() const { return _asyncKind == AsyncFunction; } + FunctionAsyncKind asyncKind() const { return _asyncKind; } void setGeneratorKind(GeneratorKind kind) { // A generator kind can be set at initialization, or when "yield" is diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index da8b1841c5ed..a7ff12a0f8e0 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -283,8 +283,9 @@ class SyntaxParseHandler bool addShorthand(Node literal, Node name, Node expr) { return true; } bool addObjectMethodDefinition(Node literal, Node name, Node fn, JSOp op) { return true; } bool addClassMethodDefinition(Node literal, Node name, Node fn, JSOp op, bool isStatic) { return true; } - Node newYieldExpression(uint32_t begin, Node value, Node gen) { return NodeUnparenthesizedYieldExpr; } + Node newYieldExpression(uint32_t begin, Node value, Node gen, JSOp op) { return NodeUnparenthesizedYieldExpr; } Node newYieldStarExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; } + Node newAwaitExpression(uint32_t begin, Node value, Node gen) { return NodeUnparenthesizedYieldExpr; } // Statements diff --git a/js/src/frontend/TokenKind.h b/js/src/frontend/TokenKind.h index 83ee7717257c..1a5d3af3c486 100644 --- a/js/src/frontend/TokenKind.h +++ b/js/src/frontend/TokenKind.h @@ -107,6 +107,8 @@ macro(THROW, "keyword 'throw'") \ macro(DEBUGGER, "keyword 'debugger'") \ macro(YIELD, "keyword 'yield'") \ + macro(ASYNC, "keyword 'async'") \ + macro(AWAIT, "keyword 'await'") \ macro(LET, "keyword 'let'") \ macro(EXPORT, "keyword 'export'") \ macro(IMPORT, "keyword 'import'") \ diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index 8b24da477305..297787d7a0c0 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -986,6 +986,11 @@ TokenStream::putIdentInTokenbuf(const char16_t* identStart) bool TokenStream::checkForKeyword(const KeywordInfo* kw, TokenKind* ttp) { + if (!awaitIsKeyword && kw->tokentype == TOK_AWAIT) { + *ttp = TOK_NAME; + return true; + } + if (kw->tokentype == TOK_RESERVED #ifndef JS_HAS_CLASSES || kw->tokentype == TOK_CLASS diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index e3601b0ba68b..ff969625ea85 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -445,6 +445,8 @@ class MOZ_STACK_CLASS TokenStream {} }; + bool awaitIsKeyword = false; + public: typedef Token::Modifier Modifier; static MOZ_CONSTEXPR_VAR Modifier None = Token::None; @@ -685,6 +687,14 @@ class MOZ_STACK_CLASS TokenStream return true; } + bool getAwaitIsKeyword() { + return awaitIsKeyword; + } + + void setAwaitIsKeyword(bool _awaitIsKeyword) { + awaitIsKeyword = _awaitIsKeyword; + } + class MOZ_STACK_CLASS Position { public: // The Token fields may contain pointers to atoms, so for correct diff --git a/js/src/js.msg b/js/src/js.msg index e4d744e4dc34..72d6faa3bca8 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -107,6 +107,7 @@ MSG_DEF(JSMSG_PROTO_NOT_OBJORNULL, 1, JSEXN_TYPEERR, "{0}.prototype is not a MSG_DEF(JSMSG_CANT_CALL_CLASS_CONSTRUCTOR, 0, JSEXN_TYPEERR, "class constructors must be invoked with |new|") MSG_DEF(JSMSG_DISABLED_DERIVED_CLASS, 1, JSEXN_INTERNALERR, "{0} temporarily disallowed in derived class constructors") MSG_DEF(JSMSG_NOT_CALLABLE, 1, JSEXN_TYPEERR, "{0} is not callable") +MSG_DEF(JSMSG_NOT_IMPLEMENTED, 1, JSEXN_INTERNALERR, "{0} is not implemented") // JSON MSG_DEF(JSMSG_JSON_BAD_PARSE, 3, JSEXN_SYNTAXERR, "JSON.parse: {0} at line {1} column {2} of the JSON data") @@ -187,6 +188,9 @@ MSG_DEF(JSMSG_ARRAY_COMP_LEFTSIDE, 0, JSEXN_SYNTAXERR, "invalid array compre MSG_DEF(JSMSG_ARRAY_INIT_TOO_BIG, 0, JSEXN_INTERNALERR, "array initialiser too large") MSG_DEF(JSMSG_AS_AFTER_IMPORT_STAR, 0, JSEXN_SYNTAXERR, "missing keyword 'as' after import *") MSG_DEF(JSMSG_AS_AFTER_RESERVED_WORD, 1, JSEXN_SYNTAXERR, "missing keyword 'as' after reserved word '{0}'") +MSG_DEF(JSMSG_ASYNC_ACCESSOR, 0, JSEXN_SYNTAXERR, "async getters and setters are not allowed") +MSG_DEF(JSMSG_ASYNC_CONSTRUCTOR, 0, JSEXN_SYNTAXERR, "constructor may not be async") +MSG_DEF(JSMSG_ASYNC_GENERATOR, 0, JSEXN_SYNTAXERR, "generator function or method may not be async") MSG_DEF(JSMSG_BAD_ANON_GENERATOR_RETURN, 0, JSEXN_TYPEERR, "anonymous generator function returns a value") MSG_DEF(JSMSG_BAD_ARROW_ARGS, 0, JSEXN_SYNTAXERR, "invalid arrow-function arguments (parentheses around the arrow-function may help)") MSG_DEF(JSMSG_BAD_BINDING, 1, JSEXN_SYNTAXERR, "redefining {0} is deprecated") @@ -268,6 +272,7 @@ MSG_DEF(JSMSG_LABEL_NOT_FOUND, 0, JSEXN_SYNTAXERR, "label not found") MSG_DEF(JSMSG_LET_CLASS_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a class") MSG_DEF(JSMSG_LET_COMP_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a comprehension variable") MSG_DEF(JSMSG_LEXICAL_DECL_NOT_IN_BLOCK, 1, JSEXN_SYNTAXERR, "{0} declaration not directly within block") +MSG_DEF(JSMSG_LINE_BREAK_AFTER_AWAIT, 0, JSEXN_SYNTAXERR, "no line break is allowed after 'await'") MSG_DEF(JSMSG_LINE_BREAK_AFTER_THROW, 0, JSEXN_SYNTAXERR, "no line break is allowed between 'throw' and its expression") MSG_DEF(JSMSG_MALFORMED_ESCAPE, 1, JSEXN_SYNTAXERR, "malformed {0} character escape sequence") MSG_DEF(JSMSG_MISSING_BINARY_DIGITS, 0, JSEXN_SYNTAXERR, "missing binary digits after '0b'") @@ -340,7 +345,9 @@ MSG_DEF(JSMSG_USE_ASM_DIRECTIVE_FAIL, 0, JSEXN_SYNTAXERR, "\"use asm\" is only MSG_DEF(JSMSG_VAR_HIDES_ARG, 1, JSEXN_TYPEERR, "variable {0} redeclares argument") MSG_DEF(JSMSG_WHILE_AFTER_DO, 0, JSEXN_SYNTAXERR, "missing while after do-loop body") MSG_DEF(JSMSG_YIELD_IN_ARROW, 0, JSEXN_SYNTAXERR, "arrow function may not contain yield") +MSG_DEF(JSMSG_YIELD_IN_ASYNC, 0, JSEXN_SYNTAXERR, "async function may not contain yield") MSG_DEF(JSMSG_YIELD_IN_DEFAULT, 0, JSEXN_SYNTAXERR, "yield in default expression") +MSG_DEF(JSMSG_AWAIT_IN_DEFAULT, 0, JSEXN_SYNTAXERR, "await in default expression") MSG_DEF(JSMSG_BAD_COLUMN_NUMBER, 0, JSEXN_RANGEERR, "column number out of range") MSG_DEF(JSMSG_COMPUTED_NAME_IN_PATTERN,0, JSEXN_SYNTAXERR, "computed property names aren't supported in this destructuring declaration") MSG_DEF(JSMSG_DEFAULT_IN_PATTERN, 0, JSEXN_SYNTAXERR, "destructuring defaults aren't supported in this destructuring declaration") diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 6e89e4b8cbe0..bc931268220d 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -944,7 +944,12 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool bodyOnly, bool lamb return nullptr; } if (!fun->isArrow()) { - if (!(fun->isStarGenerator() ? out.append("function* ") : out.append("function "))) + bool ok; + if (fun->isStarGenerator()) + ok = out.append("function* "); + else + ok = out.append("function "); + if (!ok) return nullptr; } if (fun->atom()) { diff --git a/js/src/jsfun.h b/js/src/jsfun.h index cde4e2ee88c9..e3bbc0d795ba 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -285,6 +285,13 @@ class JSFunction : public js::NativeObject flags_ |= RESOLVED_NAME; } + void setAsyncKind(js::FunctionAsyncKind asyncKind) { + if (isInterpretedLazy()) + lazyScript()->setAsyncKind(asyncKind); + else + nonLazyScript()->setAsyncKind(asyncKind); + } + JSAtom* atom() const { return hasGuessedAtom() ? nullptr : atom_.get(); } js::PropertyName* name() const { @@ -459,12 +466,18 @@ class JSFunction : public js::NativeObject return js::NotGenerator; } + js::FunctionAsyncKind asyncKind() const { + return isInterpretedLazy() ? lazyScript()->asyncKind() : nonLazyScript()->asyncKind(); + } + bool isGenerator() const { return generatorKind() != js::NotGenerator; } bool isLegacyGenerator() const { return generatorKind() == js::LegacyGenerator; } bool isStarGenerator() const { return generatorKind() == js::StarGenerator; } + bool isAsync() const { return asyncKind() == js::AsyncFunction; } + void setScript(JSScript* script_) { mutableScript() = script_; } diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 3c8d26b889f7..923b10851bbb 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -2759,6 +2759,7 @@ JSScript::linkToFunctionFromEmitter(js::ExclusiveContext* cx, JS::HandleisGeneratorExp_ = funbox->inGenexpLambda; script->setGeneratorKind(funbox->generatorKind()); + script->setAsyncKind(funbox->asyncKind()); // Link the function and the script to each other, so that StaticScopeIter // may walk the scope chain of currently compiling scripts. @@ -2849,6 +2850,7 @@ JSScript::fullyInitFromEmitter(ExclusiveContext* cx, HandleScript script, Byteco MOZ_ASSERT(script->functionNonDelazifying() == funbox->function()); MOZ_ASSERT(script->isGeneratorExp_ == funbox->inGenexpLambda); MOZ_ASSERT(script->generatorKind() == funbox->generatorKind()); + MOZ_ASSERT(script->asyncKind() == funbox->asyncKind()); } else { MOZ_ASSERT(!script->funHasExtensibleScope_); MOZ_ASSERT(!script->funNeedsDeclEnvObject_); diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 9502897df9fe..b2d340974aa2 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -873,6 +873,8 @@ class ScriptSourceObject : public NativeObject enum GeneratorKind { NotGenerator, LegacyGenerator, StarGenerator }; +enum FunctionAsyncKind { SyncFunction, AsyncFunction }; + static inline unsigned GeneratorKindAsBits(GeneratorKind generatorKind) { return static_cast(generatorKind); @@ -1167,6 +1169,8 @@ class JSScript : public js::gc::TenuredCell bool isDerivedClassConstructor_:1; + bool isAsync_:1; + // Add padding so JSScript is gc::Cell aligned. Make padding protected // instead of private to suppress -Wunused-private-field compiler warnings. protected: @@ -1433,6 +1437,12 @@ class JSScript : public js::gc::TenuredCell generatorKindBits_ = GeneratorKindAsBits(kind); } + js::FunctionAsyncKind asyncKind() const { return isAsync_ ? js::AsyncFunction : js::SyncFunction; } + + void setAsyncKind(js::FunctionAsyncKind kind) { + isAsync_ = kind == js::AsyncFunction; + } + void setNeedsHomeObject() { needsHomeObject_ = true; } @@ -2099,11 +2109,11 @@ class LazyScript : public gc::TenuredCell // Assorted bits that should really be in ScriptSourceObject. uint32_t version : 8; - uint32_t numFreeVariables : 24; + uint32_t numFreeVariables : 23; uint32_t numInnerFunctions : 20; uint32_t generatorKindBits : 2; - + uint32_t isAsync : 1; // N.B. These are booleans but need to be uint32_t to pack correctly on MSVC. // If you add another boolean here, make sure to initialze it in // LazyScript::CreateRaw(). @@ -2216,6 +2226,10 @@ class LazyScript : public gc::TenuredCell GeneratorKind generatorKind() const { return GeneratorKindFromBits(p_.generatorKindBits); } + FunctionAsyncKind asyncKind() const { return p_.isAsync ? AsyncFunction : SyncFunction; } + + void setAsyncKind(FunctionAsyncKind kind) { p_.isAsync = kind == AsyncFunction; } + bool isGenerator() const { return generatorKind() != NotGenerator; } bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; } diff --git a/js/src/tests/ecma_7/AsyncFunctions/shell.js b/js/src/tests/ecma_7/AsyncFunctions/shell.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/js/src/tests/ecma_7/AsyncFunctions/syntax.js b/js/src/tests/ecma_7/AsyncFunctions/syntax.js new file mode 100644 index 000000000000..76b2a3af0eee --- /dev/null +++ b/js/src/tests/ecma_7/AsyncFunctions/syntax.js @@ -0,0 +1,85 @@ +/* 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/. */ + +/** + * Currently only a part of async/await grammar is supported: + * - Async function statements are supported. + * - Await expressions are supported (as regular unary expressions). + * All other parts of proposal are probably not supported. + * Even the supported parts of implementation may not be 100% compliant with + * the grammar. This is to be considered a proof-of-concept implementation. + */ + +assertEq(Reflect.parse("function a() {}").body[0].async, false); +assertEq(Reflect.parse("function* a() {}").body[0].async, false); +assertEq(Reflect.parse("async function a() {}").body[0].async, true); +assertEq(Reflect.parse("() => {}").body[0].async, undefined); + +// Async generators are not allowed (with regards to spec) +assertThrows(() => Reflect.parse("async function* a() {}"), SyntaxError); + +// No line terminator after async +assertEq(Reflect.parse("async\nfunction a(){}").body[0].expression.name, "async"); + +// Async arrow functions are allowed, but not supported yet +assertThrows(() => Reflect.parse("async () => true"), SyntaxError); + +// Async function expressions +assertEq(Reflect.parse("(async function() {})()").body[0].expression.callee.async, true); +assertEq(Reflect.parse("var k = async function() {}").body[0].declarations[0].init.async, true); +assertEq(Reflect.parse("var nmd = async function named() {}").body[0].declarations[0].init.id.name, "named"); + +// Awaiting not directly inside an async function is not allowed +assertThrows(() => Reflect.parse("await 4;"), SyntaxError); +assertThrows(() => Reflect.parse("function a() { await 4; }"), SyntaxError); +assertThrows(() => Reflect.parse("function* a() { await 4; }"), SyntaxError); +assertThrows(() => Reflect.parse("async function k() { function a() { await 4; } }"), SyntaxError); + +// No line terminator after await is allowed +assertThrows(() => Reflect.parse("async function a() { await\n4; }"), SyntaxError); + +// Await is not allowed as a default expr. +assertThrows(() => Reflect.parse("async function a(k = await 3) {}"), SyntaxError); +assertThrows(() => Reflect.parse("async function a() { async function b(k = await 3) {} }"), SyntaxError); + +// Await is not legal as an identifier in an async function. +assertThrows(() => Reflect.parse("async function a() { var await = 4; }"), SyntaxError); +assertThrows(() => Reflect.parse("async function a() { return await; }"), SyntaxError); + +// Yield is not allowed in an async function / treated as identifier +assertThrows(() => Reflect.parse("async function a() { yield 3; }"), SyntaxError); + +// Await is still available as an identifier name in strict mode code. +Reflect.parse("function a() { 'use strict'; var await = 3; }"); +Reflect.parse("'use strict'; var await = 3;"); + +// Await is treated differently depending on context. Various cases. +Reflect.parse("var await = 3; async function a() { await 4; }"); +Reflect.parse("async function a() { await 4; } var await = 5"); +Reflect.parse("async function a() { function b() { return await; } }") + +Reflect.parse("async function a() { var k = { async: 4 } }"); + +Reflect.parse("function a() { await: 4 }"); + +assertEq(Reflect.parse("async function a() { await 4; }") + .body[0].body.body[0].expression.operator, "await"); + +assertEq(Reflect.parse("async function a() { async function b() { await 4; } }") + .body[0].body.body[0].body.body[0].expression.operator, "await"); + +// operator priority test +assertEq(Reflect.parse("async function a() { await 2 + 3; }") + .body[0].body.body[0].expression.left.argument.value, 2); +assertEq(Reflect.parse("async function a() { await 2 + 3; }") + .body[0].body.body[0].expression.left.operator, "await"); +assertEq(Reflect.parse("async function a() { await 2 + 3; }") + .body[0].body.body[0].expression.right.value, 3); + +// blocks and other constructions +assertEq(Reflect.parse("{ async function a() { return 2; } }") + .body[0].body[0].async, true); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index ca6eb3658391..e045462e935b 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -18,6 +18,8 @@ macro(apply, apply, "apply") \ macro(arguments, arguments, "arguments") \ macro(as, as, "as") \ + macro(async, async, "async") \ + macro(await, await, "await") \ macro(ArrayIteratorNext, ArrayIteratorNext, "ArrayIteratorNext") \ macro(ArrayType, ArrayType, "ArrayType") \ macro(ArrayValues, ArrayValues, "ArrayValues") \ diff --git a/js/src/vm/Keywords.h b/js/src/vm/Keywords.h index 4c9e1729a0c8..db599274c871 100644 --- a/js/src/vm/Keywords.h +++ b/js/src/vm/Keywords.h @@ -56,6 +56,7 @@ macro(protected, protected_, TOK_STRICT_RESERVED, JSVERSION_DEFAULT) \ macro(public, public_, TOK_STRICT_RESERVED, JSVERSION_DEFAULT) \ macro(static, static_, TOK_STRICT_RESERVED, JSVERSION_DEFAULT) \ + macro(await, await, TOK_AWAIT, JSVERSION_DEFAULT) \ /* \ * Yield is a token inside function*. Outside of a function*, it is a \ * future reserved keyword in strict mode, but a keyword in JS1.7 even \ diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h index f39cf4e8a162..dbb4fc8bf62b 100644 --- a/js/src/vm/Xdr.h +++ b/js/src/vm/Xdr.h @@ -33,7 +33,7 @@ static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 311; static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND); -static_assert(JSErr_Limit == 418, +static_assert(JSErr_Limit == 425, "GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or " "removed MSG_DEFs from js.msg, you should increment " "XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's " From 986d54fb1c879e40dd641622529ff736d979613b Mon Sep 17 00:00:00 2001 From: Mariusz Kierski Date: Mon, 5 Oct 2015 13:24:03 -0700 Subject: [PATCH 035/228] Bug 1185106 - Part 4: Implement async functions. (r=efaust, r=jandem) --- js/src/Makefile.in | 1 + js/src/builtin/AsyncFunctions.js | 46 +++++ js/src/frontend/BytecodeEmitter.cpp | 67 +++++-- js/src/frontend/BytecodeEmitter.h | 2 + js/src/jit/BaselineCompiler.cpp | 8 +- js/src/jit/CodeGenerator.cpp | 3 +- js/src/jit/IonBuilder.cpp | 8 +- js/src/jit/Lowering.cpp | 6 +- js/src/jit/MIR.h | 19 +- js/src/jit/shared/LIR-shared.h | 12 +- js/src/jsfun.h | 2 +- js/src/tests/ecma_7/AsyncFunctions/1.1.1.js | 18 ++ js/src/tests/ecma_7/AsyncFunctions/1.1.2.js | 13 ++ js/src/tests/ecma_7/AsyncFunctions/methods.js | 56 ++++++ .../tests/ecma_7/AsyncFunctions/semantics.js | 168 ++++++++++++++++++ js/src/tests/ecma_7/AsyncFunctions/shell.js | 27 +++ .../ecma_7/AsyncFunctions/syntax-modules.js | 8 + js/src/vm/Interpreter.cpp | 15 +- js/src/vm/Opcodes.h | 3 +- js/src/vm/ScopeObject.cpp | 7 +- 20 files changed, 436 insertions(+), 53 deletions(-) create mode 100644 js/src/builtin/AsyncFunctions.js create mode 100644 js/src/tests/ecma_7/AsyncFunctions/1.1.1.js create mode 100644 js/src/tests/ecma_7/AsyncFunctions/1.1.2.js create mode 100644 js/src/tests/ecma_7/AsyncFunctions/methods.js create mode 100644 js/src/tests/ecma_7/AsyncFunctions/semantics.js create mode 100644 js/src/tests/ecma_7/AsyncFunctions/syntax-modules.js diff --git a/js/src/Makefile.in b/js/src/Makefile.in index 7c5156ffbed4..8d45c370dc22 100644 --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -284,6 +284,7 @@ selfhosting:: selfhosted.out.h selfhosting_srcs := \ $(srcdir)/builtin/Utilities.js \ $(srcdir)/builtin/Array.js \ + $(srcdir)/builtin/AsyncFunctions.js \ $(srcdir)/builtin/Date.js \ $(srcdir)/builtin/Error.js \ $(srcdir)/builtin/Generator.js \ diff --git a/js/src/builtin/AsyncFunctions.js b/js/src/builtin/AsyncFunctions.js new file mode 100644 index 000000000000..0f918d3a9f98 --- /dev/null +++ b/js/src/builtin/AsyncFunctions.js @@ -0,0 +1,46 @@ +/* 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/. */ + +function AsyncFunction_wrap(genFunction) { + var wrapper = function() { + // The try block is required to handle throws in default arguments properly. + try { + return AsyncFunction_start(callFunction(std_Function_apply, genFunction, this, arguments)); + } catch (e) { + return Promise_reject(e); + } + }; + SetFunctionExtendedSlot(genFunction, 1, wrapper); + var name = GetFunName(genFunction); + if (typeof name !== 'undefined') + SetFunName(wrapper, name); + return wrapper; +} + +function AsyncFunction_start(generator) { + return AsyncFunction_resume(generator, undefined, generator.next); +} + +function AsyncFunction_resume(gen, v, method) { + let result; + try { + // get back into async function, run to next await point + result = callFunction(method, gen, v); + } catch (exc) { + // The async function itself failed. + return Promise_reject(exc); + } + + if (result.done) + return Promise_resolve(result.value); + + // If we get here, `await` occurred. `gen` is paused at a yield point. + return callFunction(Promise_then, + Promise_resolve(result.value), + function(val) { + return AsyncFunction_resume(gen, val, gen.next); + }, function (err) { + return AsyncFunction_resume(gen, err, gen.throw); + }); +} diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 5dad148c7cc4..e53ea56fb1c3 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -240,7 +240,6 @@ bool BytecodeEmitter::emit1(JSOp op) { MOZ_ASSERT(checkStrictOrSloppy(op)); - ptrdiff_t offset; if (!emitCheck(1, &offset)) return false; @@ -1991,7 +1990,6 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) case PNK_PREDECREMENT: case PNK_POSTDECREMENT: case PNK_THROW: - case PNK_AWAIT: MOZ_ASSERT(pn->isArity(PN_UNARY)); *answer = true; return true; @@ -2013,6 +2011,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) case PNK_YIELD_STAR: case PNK_YIELD: + case PNK_AWAIT: MOZ_ASSERT(pn->isArity(PN_BINARY)); *answer = true; return true; @@ -5858,6 +5857,16 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto) MOZ_ASSERT(pn->getOp() == JSOP_LAMBDA); pn->setOp(JSOP_FUNWITHPROTO); } + + if (funbox->isAsync()) + return emitAsyncWrapper(index, funbox->needsHomeObject()); + + if (pn->getOp() == JSOP_DEFFUN) { + if (!emitIndex32(JSOP_LAMBDA, index)) + return false; + return emit1(JSOP_DEFFUN); + } + return emitIndex32(pn->getOp(), index); } @@ -5877,7 +5886,14 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto) MOZ_ASSERT(pn->getOp() == JSOP_NOP); MOZ_ASSERT(atBodyLevel()); switchToPrologue(); - if (!emitIndex32(JSOP_DEFFUN, index)) + if (funbox->isAsync()) { + if (!emitAsyncWrapper(index, fun->isMethod())) + return false; + } else { + if (!emitIndex32(JSOP_LAMBDA, index)) + return false; + } + if (!emit1(JSOP_DEFFUN)) return false; if (!updateSourceCoordNotes(pn->pn_pos.begin)) return false; @@ -5891,7 +5907,11 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto) bi->kind() == Binding::ARGUMENT); MOZ_ASSERT(bi.argOrLocalIndex() < JS_BIT(20)); #endif - if (!emitIndexOp(JSOP_LAMBDA, index)) + if (funbox->isAsync()) { + if (!emitAsyncWrapper(index, false)) + return false; + } + else if (!emitIndexOp(JSOP_LAMBDA, index)) return false; MOZ_ASSERT(pn->getOp() == JSOP_GETLOCAL || pn->getOp() == JSOP_GETARG); JSOp setOp = pn->getOp() == JSOP_GETLOCAL ? JSOP_SETLOCAL : JSOP_SETARG; @@ -5904,6 +5924,30 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto) return true; } +bool +BytecodeEmitter::emitAsyncWrapper(unsigned index, bool needsHomeObject) { + JSAtom* atom = Atomize(cx, "AsyncFunction_wrap", 18); + if (!atom) + return false; + /* TODO Comment */ + if (needsHomeObject && !emitIndex32(JSOP_LAMBDA, index)) + return false; + if (!emitAtomOp(atom, JSOP_GETINTRINSIC)) + return false; + if (!emit1(JSOP_UNDEFINED)) + return false; + if (needsHomeObject) { + if (!emitDupAt(2)) + return false; + } else { + if (!emitIndex32(JSOP_LAMBDA, index)) + return false; + } + if (!emitCall(JSOP_CALL, 1)) + return false; + return true; +} + bool BytecodeEmitter::emitDo(ParseNode* pn) { @@ -7070,7 +7114,12 @@ BytecodeEmitter::emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp, propdef->pn_right->pn_funbox->needsHomeObject()) { MOZ_ASSERT(propdef->pn_right->pn_funbox->function()->allowSuperProperty()); - if (!emit2(JSOP_INITHOMEOBJECT, isIndex)) + bool isAsync = propdef->pn_right->pn_funbox->isAsync(); + if (isAsync && !emit1(JSOP_SWAP)) + return false; + if (!emit2(JSOP_INITHOMEOBJECT, isIndex + isAsync)) + return false; + if (isAsync && !emit1(JSOP_POP)) return false; } @@ -7689,6 +7738,7 @@ BytecodeEmitter::emitTree(ParseNode* pn) break; case PNK_YIELD: + case PNK_AWAIT: ok = emitYield(pn); break; @@ -8022,13 +8072,6 @@ BytecodeEmitter::emitTree(ParseNode* pn) return false; break; - // PNK_AWAIT handling is not yet implemented (in this part), - // so currently we just return "true" as a placeholder. - case PNK_AWAIT: - if (!emit1(JSOP_TRUE)) - return false; - break; - case PNK_POSHOLDER: MOZ_ASSERT_UNREACHABLE("Should never try to emit PNK_POSHOLDER"); diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index 44fe9cb06461..25afd64df7a2 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -482,6 +482,8 @@ struct BytecodeEmitter bool emitPropOp(ParseNode* pn, JSOp op); bool emitPropIncDec(ParseNode* pn); + bool emitAsyncWrapper(unsigned index, bool isMethod); + bool emitComputedPropertyName(ParseNode* computedPropName); // Emit bytecode to put operands for a JSOP_GETELEM/CALLELEM/SETELEM/DELELEM diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index 8bd153bf2b17..1fb654143a52 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -2496,15 +2496,15 @@ static const VMFunction DefFunOperationInfo = FunctionInfo(De bool BaselineCompiler::emit_JSOP_DEFFUN() { - RootedFunction fun(cx, script->getFunction(GET_UINT32_INDEX(pc))); - frame.syncStack(0); - masm.loadPtr(frame.addressOfScopeChain(), R0.scratchReg()); + frame.popRegsAndSync(1); + masm.unboxObject(R0, R0.scratchReg()); + masm.loadPtr(frame.addressOfScopeChain(), R1.scratchReg()); prepareVMCall(); - pushArg(ImmGCPtr(fun)); pushArg(R0.scratchReg()); + pushArg(R1.scratchReg()); pushArg(ImmGCPtr(script)); return callVM(DefFunOperationInfo); diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index befb0a9703a5..034ebb77a50f 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -3737,8 +3737,9 @@ void CodeGenerator::visitDefFun(LDefFun* lir) { Register scopeChain = ToRegister(lir->scopeChain()); + Register fun = ToRegister(lir->fun()); - pushArg(ImmGCPtr(lir->mir()->fun())); + pushArg(fun); pushArg(scopeChain); pushArg(ImmGCPtr(current->mir()->info().script())); diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 9dd58efe9e1a..05220414063f 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -12585,13 +12585,11 @@ IonBuilder::jsop_defvar(uint32_t index) bool IonBuilder::jsop_deffun(uint32_t index) { - JSFunction* fun = script()->getFunction(index); - if (fun->isNative() && IsAsmJSModuleNative(fun->native())) - return abort("asm.js module function"); - MOZ_ASSERT(analysis().usesScopeChain()); - MDefFun* deffun = MDefFun::New(alloc(), fun, current->scopeChain()); + MDefinition *funDef = current->pop(); + + MDefFun* deffun = MDefFun::New(alloc(), funDef, current->scopeChain()); current->add(deffun); return resumeAfter(deffun); diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index bae8688a4434..95ffc97efc04 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -156,7 +156,11 @@ LIRGenerator::visitDefVar(MDefVar* ins) void LIRGenerator::visitDefFun(MDefFun* ins) { - LDefFun* lir = new(alloc()) LDefFun(useRegisterAtStart(ins->scopeChain())); + MDefinition* fun = ins->fun(); + MOZ_ASSERT(fun->type() == MIRType_Object); + + LDefFun* lir = new(alloc()) LDefFun(useRegisterAtStart(fun), + useRegisterAtStart(ins->scopeChain())); add(lir, ins); assignSafepoint(lir, ins); } diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 40779372ce96..2f7779ff14a1 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -7319,29 +7319,26 @@ class MDefVar }; class MDefFun - : public MUnaryInstruction, - public NoTypePolicy::Data + : public MBinaryInstruction, + public ObjectPolicy<0>::Data { - CompilerFunction fun_; - private: - MDefFun(JSFunction* fun, MDefinition* scopeChain) - : MUnaryInstruction(scopeChain), - fun_(fun) + MDefFun(MDefinition* fun, MDefinition* scopeChain) + : MBinaryInstruction(fun, scopeChain) {} public: INSTRUCTION_HEADER(DefFun) - static MDefFun* New(TempAllocator& alloc, JSFunction* fun, MDefinition* scopeChain) { + static MDefFun* New(TempAllocator& alloc, MDefinition* fun, MDefinition* scopeChain) { return new(alloc) MDefFun(fun, scopeChain); } - JSFunction* fun() const { - return fun_; + MDefinition* fun() const { + return getOperand(0); } MDefinition* scopeChain() const { - return getOperand(0); + return getOperand(1); } bool possiblyCalls() const override { return true; diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h index 56f5416d97eb..f4a77ef30340 100644 --- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -1228,19 +1228,23 @@ class LDefVar : public LCallInstructionHelper<0, 1, 0> } }; -class LDefFun : public LCallInstructionHelper<0, 1, 0> +class LDefFun : public LCallInstructionHelper<0, 2, 0> { public: LIR_HEADER(DefFun) - explicit LDefFun(const LAllocation& scopeChain) + LDefFun(const LAllocation& fun, const LAllocation& scopeChain) { - setOperand(0, scopeChain); + setOperand(0, fun); + setOperand(1, scopeChain); } - const LAllocation* scopeChain() { + const LAllocation* fun() { return getOperand(0); } + const LAllocation* scopeChain() { + return getOperand(1); + } MDefFun* mir() const { return mir_->toDefFun(); } diff --git a/js/src/jsfun.h b/js/src/jsfun.h index e3bbc0d795ba..5ff6ed859222 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -467,7 +467,7 @@ class JSFunction : public js::NativeObject } js::FunctionAsyncKind asyncKind() const { - return isInterpretedLazy() ? lazyScript()->asyncKind() : nonLazyScript()->asyncKind(); + return isInterpretedLazy() ? lazyScript()->asyncKind() : nonLazyScript()->asyncKind(); } bool isGenerator() const { return generatorKind() != js::NotGenerator; } diff --git a/js/src/tests/ecma_7/AsyncFunctions/1.1.1.js b/js/src/tests/ecma_7/AsyncFunctions/1.1.1.js new file mode 100644 index 000000000000..549646eee225 --- /dev/null +++ b/js/src/tests/ecma_7/AsyncFunctions/1.1.1.js @@ -0,0 +1,18 @@ +/* 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/. */ + +function assertThrowsSE(code) { + assertThrows(() => Reflect.parse(code), SyntaxError); +} + +assertThrowsSE("'use strict'; async function eval() {}"); +assertThrowsSE("'use strict'; async function arguments() {}"); +assertThrowsSE("async function a(k = super.prop) { }"); +assertThrowsSE("async function a() { super.prop(); }"); +assertThrowsSE("async function a() { super(); }"); + +assertThrowsSE("async function a(k = await 3) {}"); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_7/AsyncFunctions/1.1.2.js b/js/src/tests/ecma_7/AsyncFunctions/1.1.2.js new file mode 100644 index 000000000000..c73e14df294c --- /dev/null +++ b/js/src/tests/ecma_7/AsyncFunctions/1.1.2.js @@ -0,0 +1,13 @@ +/* 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/. */ + +async function test() { } + +var anon = async function() { } + +assertEq(test.name, "test"); +assertEq(anon.name, ""); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_7/AsyncFunctions/methods.js b/js/src/tests/ecma_7/AsyncFunctions/methods.js new file mode 100644 index 000000000000..68adc4e9d352 --- /dev/null +++ b/js/src/tests/ecma_7/AsyncFunctions/methods.js @@ -0,0 +1,56 @@ +/* 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 Promise = ShellPromise; + +class X { + constructor() { + this.value = 42; + } + async getValue() { + return this.value; + } + setValue(value) { + this.value = value; + } + async increment() { + var value = await this.getValue(); + this.setValue(value + 1); + return this.getValue(); + } + async getBaseClassName() { + return 'X'; + } + static async getStaticValue() { + return 44; + } +} + +class Y extends X { + constructor() { } + async getBaseClassName() { + return super.getBaseClassName(); + } +} + +var objLiteral = { + async get() { + return 45; + }, + someStuff: 5 +}; + +var x = new X(); +var y = new Y(); + +Promise.all([ + assertEventuallyEq(x.getValue(), 42), + assertEventuallyEq(x.increment(), 43), + assertEventuallyEq(X.getStaticValue(), 44), + assertEventuallyEq(objLiteral.get(), 45), + assertEventuallyEq(y.getBaseClassName(), 'X'), +]).then(() => { + if (typeof reportCompare === "function") + reportCompare(true, true); +}); diff --git a/js/src/tests/ecma_7/AsyncFunctions/semantics.js b/js/src/tests/ecma_7/AsyncFunctions/semantics.js new file mode 100644 index 000000000000..311d71cf12a9 --- /dev/null +++ b/js/src/tests/ecma_7/AsyncFunctions/semantics.js @@ -0,0 +1,168 @@ +/* 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 Promise = ShellPromise; + +async function empty() { + +} + +async function simpleReturn() { + return 1; +} + +async function simpleAwait() { + var result = await 2; + return result; +} + +async function simpleAwaitAsync() { + var result = await simpleReturn(); + return 2 + result; +} + +async function returnOtherAsync() { + return 1 + await simpleAwaitAsync(); +} + +async function simpleThrower() { + throw new Error(); +} + +async function delegatedThrower() { + var val = await simpleThrower(); + return val; +} + +async function tryCatch() { + try { + await delegatedThrower(); + return 'FAILED'; + } catch (_) { + return 5; + } +} + +async function tryCatchThrow() { + try { + await delegatedThrower(); + return 'FAILED'; + } catch (_) { + return delegatedThrower(); + } +} + +async function wellFinally() { + try { + await delegatedThrower(); + } catch (_) { + return 'FAILED'; + } finally { + return 6; + } +} + +async function finallyMayFail() { + try { + await delegatedThrower(); + } catch (_) { + return 5; + } finally { + return delegatedThrower(); + } +} + +async function embedded() { + async function inner() { + return 7; + } + return await inner(); +} + +// recursion, it works! +async function fib(n) { + return (n == 0 || n == 1) ? n : await fib(n - 1) + await fib(n - 2); +} + +// mutual recursion +async function isOdd(n) { + async function isEven(n) { + return n === 0 || await isOdd(n - 1); + } + return n !== 0 && await isEven(n - 1); +} + +// recursion, take three! +var hardcoreFib = async function fib2(n) { + return (n == 0 || n == 1) ? n : await fib2(n - 1) + await fib2(n - 2); +} + +var asyncExpr = async function() { + return 10; +} + +var namedAsyncExpr = async function simple() { + return 11; +} + +async function executionOrder() { + var value = 0; + async function first() { + return (value = value === 0 ? 1 : value); + } + async function second() { + return (value = value === 0 ? 2 : value); + } + async function third() { + return (value = value === 0 ? 3 : value); + } + return await first() + await second() + await third() + 6; +} + +async function miscellaneous() { + if (arguments.length === 3 && + arguments.callee.name === "miscellaneous") + return 14; +} + +function thrower() { + throw 15; +} + +async function defaultArgs(arg = thrower()) { + +} + +// Async functions are not constructible +assertThrows(() => { + async function Person() { + + } + new Person(); +}, TypeError); + +Promise.all([ + assertEventuallyEq(empty(), undefined), + assertEventuallyEq(simpleReturn(), 1), + assertEventuallyEq(simpleAwait(), 2), + assertEventuallyEq(simpleAwaitAsync(), 3), + assertEventuallyEq(returnOtherAsync(), 4), + assertEventuallyThrows(simpleThrower(), Error), + assertEventuallyEq(tryCatch(), 5), + assertEventuallyThrows(tryCatchThrow(), Error), + assertEventuallyEq(wellFinally(), 6), + assertEventuallyThrows(finallyMayFail(), Error), + assertEventuallyEq(embedded(), 7), + assertEventuallyEq(fib(6), 8), + assertEventuallyEq(executionOrder(), 9), + assertEventuallyEq(asyncExpr(), 10), + assertEventuallyEq(namedAsyncExpr(), 11), + assertEventuallyEq(isOdd(12).then(v => v ? "oops" : 12), 12), + assertEventuallyEq(hardcoreFib(7), 13), + assertEventuallyEq(miscellaneous(1, 2, 3), 14), + assertEventuallyEq(defaultArgs().catch(e => e), 15) +]).then(() => { + if (typeof reportCompare === "function") + reportCompare(true, true); +}); diff --git a/js/src/tests/ecma_7/AsyncFunctions/shell.js b/js/src/tests/ecma_7/AsyncFunctions/shell.js index e69de29bb2d1..3d9550cd9a7a 100644 --- a/js/src/tests/ecma_7/AsyncFunctions/shell.js +++ b/js/src/tests/ecma_7/AsyncFunctions/shell.js @@ -0,0 +1,27 @@ +/* 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/. */ + +/** + * These methods are inspired by chai-as-promised library for promise testing + * in JS applications. They check if promises eventually resolve to a given value + * or are rejected with a specified error type. + */ + +if (typeof assertEventuallyEq === 'undefined') { + assertEventuallyEq = function(promise, expected) { + return promise.then(actual => assertEq(actual, expected)); + }; +} + +if (typeof assertEventuallyThrows === 'undefined') { + assertEventuallyThrows = function(promise, expectedErrorType) { + return promise.catch(actualE => assertEq(actualE instanceof expectedErrorType, true)); + }; +} + +if (typeof assertEventuallyDeepEq === 'undefined') { + assertEventuallyDeepEq = function(promise, expected) { + return promise.then(actual => assertDeepEq(actual, expected)); + }; +} diff --git a/js/src/tests/ecma_7/AsyncFunctions/syntax-modules.js b/js/src/tests/ecma_7/AsyncFunctions/syntax-modules.js new file mode 100644 index 000000000000..cce6d15c3826 --- /dev/null +++ b/js/src/tests/ecma_7/AsyncFunctions/syntax-modules.js @@ -0,0 +1,8 @@ +parseModule("async function f() { await 3; }"); +parseModule("async function f() { await 3; }"); +assertThrows(() => parseModule("var await = 5;"), SyntaxError); +assertThrows(() => parseModule("export var await;"), SyntaxError); +assertThrows(() => parseModule("async function f() { function g() { await 3; } }"), SyntaxError); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 5a32a10e138d..061a4850fb79 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -3507,17 +3507,18 @@ CASE(JSOP_DEFVAR) } END_CASE(JSOP_DEFVAR) -CASE(JSOP_DEFFUN) -{ +CASE(JSOP_DEFFUN) { /* * A top-level function defined in Global or Eval code (see ECMA-262 * Ed. 3), or else a SpiderMonkey extension: a named function statement in * a compound statement (not at the top statement level of global code, or * at the top level of a function body). */ - ReservedRooted fun(&rootFunction0, script->getFunction(GET_UINT32_INDEX(REGS.pc))); + MOZ_ASSERT(REGS.sp[-1].isObject()); + ReservedRooted fun(&rootFunction0, ®S.sp[-1].toObject().as()); if (!DefFunOperation(cx, script, REGS.fp()->scopeChain(), fun)) goto error; + REGS.sp--; } END_CASE(JSOP_DEFFUN) @@ -4321,14 +4322,6 @@ js::DefFunOperation(JSContext* cx, HandleScript script, HandleObject scopeChain, * requests in server-side JS. */ RootedFunction fun(cx, funArg); - if (fun->isNative() || fun->environment() != scopeChain) { - fun = CloneFunctionObjectIfNotSingleton(cx, fun, scopeChain, nullptr, TenuredObject); - if (!fun) - return false; - } else { - MOZ_ASSERT(script->treatAsRunOnce()); - MOZ_ASSERT(!script->functionNonDelazifying()); - } /* * We define the function as a property of the variable object and not the diff --git a/js/src/vm/Opcodes.h b/js/src/vm/Opcodes.h index fc5d0e0a791e..766278e2d46a 100644 --- a/js/src/vm/Opcodes.h +++ b/js/src/vm/Opcodes.h @@ -1294,7 +1294,7 @@ * Operands: uint32_t funcIndex * Stack: => */ \ - macro(JSOP_DEFFUN, 127,"deffun", NULL, 5, 0, 0, JOF_OBJECT) \ + macro(JSOP_DEFFUN, 127,"deffun", NULL, 1, 1, 0, JOF_BYTE) \ /* * Defines the new binding on the frame's current variables-object (the * scope object on the scope chain designated to receive new variables) with @@ -1983,7 +1983,6 @@ * Stack: val => ToString(val) */ \ macro(JSOP_TOSTRING, 228, "tostring", NULL, 1, 1, 1, JOF_BYTE) - /* * In certain circumstances it may be useful to "pad out" the opcode space to * a power of two. Use this macro to do so. diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 9af4614a485d..8ef58d00cace 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -237,7 +237,12 @@ CallObject::createForFunction(JSContext* cx, HandleObject enclosing, HandleFunct * object holding function's name. */ if (callee->isNamedLambda()) { - scopeChain = DeclEnvObject::create(cx, scopeChain, callee); + if (callee->isAsync()) { + RootedFunction fun(cx, &callee->getExtendedSlot(1).toObject().as()); + scopeChain = DeclEnvObject::create(cx, scopeChain, fun); + } else { + scopeChain = DeclEnvObject::create(cx, scopeChain, callee); + } if (!scopeChain) return nullptr; } From dd6c5231fd6a037d2005d63469e0f633eb940d5a Mon Sep 17 00:00:00 2001 From: Eric Faust Date: Mon, 5 Oct 2015 13:24:03 -0700 Subject: [PATCH 036/228] Bug 1185106 - Follow up: Clean up NIGHTLY_ONLY handling for async functions, and allow tests to pass on uplift. (r=Waldo) --- js/src/frontend/Parser.cpp | 10 +- js/src/jit-test/lib/class.js | 3 +- js/src/jsversion.h | 3 + js/src/tests/ecma_6/shell.js | 11 -- js/src/tests/ecma_7/AsyncFunctions/1.1.1.js | 14 ++- js/src/tests/ecma_7/AsyncFunctions/1.1.2.js | 7 ++ js/src/tests/ecma_7/AsyncFunctions/methods.js | 9 ++ .../tests/ecma_7/AsyncFunctions/semantics.js | 9 ++ js/src/tests/ecma_7/AsyncFunctions/shell.js | 9 ++ .../ecma_7/AsyncFunctions/syntax-modules.js | 12 +- js/src/tests/ecma_7/AsyncFunctions/syntax.js | 106 +++++++++--------- js/src/tests/shell.js | 11 ++ 12 files changed, 125 insertions(+), 79 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 0e61f90e5dce..9221f99e9bed 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -6806,7 +6806,7 @@ Parser::statement(YieldHandling yieldHandling, bool canHaveDirecti TokenKind next; TokenKind nextSameLine = TOK_EOF; -#ifdef NIGHTLY_BUILD +#ifdef JS_HAS_ASYNC_FUNCS if (tokenStream.currentName() == context->names().async) { if (!tokenStream.peekTokenSameLine(&nextSameLine)) return null(); @@ -7207,7 +7207,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl if (tt == TOK_NAME) { TokenKind nextSameLine = TOK_EOF; -#ifdef NIGHTLY_BUILD +#ifdef JS_HAS_ASYNC_FUNCS if (tokenStream.currentName() == context->names().async) { if (!tokenStream.peekTokenSameLine(&nextSameLine)) return null(); @@ -7570,9 +7570,12 @@ Parser::unaryExpr(YieldHandling yieldHandling, InvokedPrediction i case TOK_AWAIT: { +#ifndef JS_HAS_ASYNC_FUNCS + MOZ_CRASH("Should not see TOK_AWAIT without async function support"); +#endif + TokenKind nextSameLine = TOK_EOF; -#ifdef NIGHTLY_BUILD if (!tokenStream.peekTokenSameLine(&nextSameLine, TokenStream::Operand)) return null(); if (nextSameLine != TOK_EOL) { @@ -7584,7 +7587,6 @@ Parser::unaryExpr(YieldHandling yieldHandling, InvokedPrediction i report(ParseError, false, null(), JSMSG_LINE_BREAK_AFTER_AWAIT); return null(); } -#endif } default: { diff --git a/js/src/jit-test/lib/class.js b/js/src/jit-test/lib/class.js index eea50788a4d2..0f5860c5d107 100644 --- a/js/src/jit-test/lib/class.js +++ b/js/src/jit-test/lib/class.js @@ -1 +1,2 @@ -load(libdir + "../../tests/ecma_6/shell.js"); +// classesEnabled ended up needing a fairly broad scope. +load(libdir + "../../tests/shell.js"); diff --git a/js/src/jsversion.h b/js/src/jsversion.h index 59fbc3815ce3..614ce255105e 100644 --- a/js/src/jsversion.h +++ b/js/src/jsversion.h @@ -46,6 +46,9 @@ /* Support for ES7 Exponentiation proposal. */ #define JS_HAS_EXPONENTIATION 1 +/* Support for ES7 Async Functions. */ +#define JS_HAS_ASYNC_FUNCS 1 + #endif // NIGHTLY_BUILD #endif /* jsversion_h */ diff --git a/js/src/tests/ecma_6/shell.js b/js/src/tests/ecma_6/shell.js index 887bb0c015a4..1d5d37460759 100644 --- a/js/src/tests/ecma_6/shell.js +++ b/js/src/tests/ecma_6/shell.js @@ -215,14 +215,3 @@ if (typeof assertWarning === 'undefined') { disableLastWarning(); } } - -function classesEnabled(testCode = "class Foo { constructor() {} }") { - try { - new Function(testCode); - return true; - } catch (e) { - if (!(e instanceof SyntaxError)) - throw e; - return false; - } -} diff --git a/js/src/tests/ecma_7/AsyncFunctions/1.1.1.js b/js/src/tests/ecma_7/AsyncFunctions/1.1.1.js index 549646eee225..827ed54563fb 100644 --- a/js/src/tests/ecma_7/AsyncFunctions/1.1.1.js +++ b/js/src/tests/ecma_7/AsyncFunctions/1.1.1.js @@ -6,13 +6,15 @@ function assertThrowsSE(code) { assertThrows(() => Reflect.parse(code), SyntaxError); } -assertThrowsSE("'use strict'; async function eval() {}"); -assertThrowsSE("'use strict'; async function arguments() {}"); -assertThrowsSE("async function a(k = super.prop) { }"); -assertThrowsSE("async function a() { super.prop(); }"); -assertThrowsSE("async function a() { super(); }"); +if (asyncFunctionsEnabled()) { + assertThrowsSE("'use strict'; async function eval() {}"); + assertThrowsSE("'use strict'; async function arguments() {}"); + assertThrowsSE("async function a(k = super.prop) { }"); + assertThrowsSE("async function a() { super.prop(); }"); + assertThrowsSE("async function a() { super(); }"); -assertThrowsSE("async function a(k = await 3) {}"); + assertThrowsSE("async function a(k = await 3) {}"); +} if (typeof reportCompare === "function") reportCompare(true, true); diff --git a/js/src/tests/ecma_7/AsyncFunctions/1.1.2.js b/js/src/tests/ecma_7/AsyncFunctions/1.1.2.js index c73e14df294c..c299243e129a 100644 --- a/js/src/tests/ecma_7/AsyncFunctions/1.1.2.js +++ b/js/src/tests/ecma_7/AsyncFunctions/1.1.2.js @@ -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/. */ +var test = ` + async function test() { } var anon = async function() { } @@ -9,5 +11,10 @@ var anon = async function() { } assertEq(test.name, "test"); assertEq(anon.name, ""); +`; + +if (asyncFunctionsEnabled()) + eval(test); + if (typeof reportCompare === "function") reportCompare(true, true); diff --git a/js/src/tests/ecma_7/AsyncFunctions/methods.js b/js/src/tests/ecma_7/AsyncFunctions/methods.js index 68adc4e9d352..b749398e67bd 100644 --- a/js/src/tests/ecma_7/AsyncFunctions/methods.js +++ b/js/src/tests/ecma_7/AsyncFunctions/methods.js @@ -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/. */ +var test = ` + var Promise = ShellPromise; class X { @@ -54,3 +56,10 @@ Promise.all([ if (typeof reportCompare === "function") reportCompare(true, true); }); + +`; + +if (classesEnabled() && asyncFunctionsEnabled()) + eval(test); +else if (typeof reportCompare === 'function') + reportCompare(0,0,"OK"); diff --git a/js/src/tests/ecma_7/AsyncFunctions/semantics.js b/js/src/tests/ecma_7/AsyncFunctions/semantics.js index 311d71cf12a9..d039e2cb37a3 100644 --- a/js/src/tests/ecma_7/AsyncFunctions/semantics.js +++ b/js/src/tests/ecma_7/AsyncFunctions/semantics.js @@ -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/. */ +var test = ` + var Promise = ShellPromise; async function empty() { @@ -166,3 +168,10 @@ Promise.all([ if (typeof reportCompare === "function") reportCompare(true, true); }); + +`; + +if (asyncFunctionsEnabled()) + eval(test); +else if (typeof reportCompare === 'function') + reportCompare(0,0,"OK"); diff --git a/js/src/tests/ecma_7/AsyncFunctions/shell.js b/js/src/tests/ecma_7/AsyncFunctions/shell.js index 3d9550cd9a7a..bedaac504195 100644 --- a/js/src/tests/ecma_7/AsyncFunctions/shell.js +++ b/js/src/tests/ecma_7/AsyncFunctions/shell.js @@ -25,3 +25,12 @@ if (typeof assertEventuallyDeepEq === 'undefined') { return promise.then(actual => assertDeepEq(actual, expected)); }; } + +function asyncFunctionsEnabled() { + try { + eval("async function f() { }"); + return true; + } catch (e if e instanceof SyntaxError) { + return false; + } +} diff --git a/js/src/tests/ecma_7/AsyncFunctions/syntax-modules.js b/js/src/tests/ecma_7/AsyncFunctions/syntax-modules.js index cce6d15c3826..f3d666b71f01 100644 --- a/js/src/tests/ecma_7/AsyncFunctions/syntax-modules.js +++ b/js/src/tests/ecma_7/AsyncFunctions/syntax-modules.js @@ -1,8 +1,10 @@ -parseModule("async function f() { await 3; }"); -parseModule("async function f() { await 3; }"); -assertThrows(() => parseModule("var await = 5;"), SyntaxError); -assertThrows(() => parseModule("export var await;"), SyntaxError); -assertThrows(() => parseModule("async function f() { function g() { await 3; } }"), SyntaxError); +if (asyncFunctionsEnabled()) { + parseModule("async function f() { await 3; }"); + parseModule("async function f() { await 3; }"); + assertThrows(() => parseModule("var await = 5;"), SyntaxError); + assertThrows(() => parseModule("export var await;"), SyntaxError); + assertThrows(() => parseModule("async function f() { function g() { await 3; } }"), SyntaxError); +} if (typeof reportCompare === "function") reportCompare(true, true); diff --git a/js/src/tests/ecma_7/AsyncFunctions/syntax.js b/js/src/tests/ecma_7/AsyncFunctions/syntax.js index 76b2a3af0eee..5723fa5a3a7b 100644 --- a/js/src/tests/ecma_7/AsyncFunctions/syntax.js +++ b/js/src/tests/ecma_7/AsyncFunctions/syntax.js @@ -11,75 +11,77 @@ * the grammar. This is to be considered a proof-of-concept implementation. */ -assertEq(Reflect.parse("function a() {}").body[0].async, false); -assertEq(Reflect.parse("function* a() {}").body[0].async, false); -assertEq(Reflect.parse("async function a() {}").body[0].async, true); -assertEq(Reflect.parse("() => {}").body[0].async, undefined); +if (asyncFunctionsEnabled()) { + assertEq(Reflect.parse("function a() {}").body[0].async, false); + assertEq(Reflect.parse("function* a() {}").body[0].async, false); + assertEq(Reflect.parse("async function a() {}").body[0].async, true); + assertEq(Reflect.parse("() => {}").body[0].async, undefined); -// Async generators are not allowed (with regards to spec) -assertThrows(() => Reflect.parse("async function* a() {}"), SyntaxError); + // Async generators are not allowed (with regards to spec) + assertThrows(() => Reflect.parse("async function* a() {}"), SyntaxError); -// No line terminator after async -assertEq(Reflect.parse("async\nfunction a(){}").body[0].expression.name, "async"); + // No line terminator after async + assertEq(Reflect.parse("async\nfunction a(){}").body[0].expression.name, "async"); -// Async arrow functions are allowed, but not supported yet -assertThrows(() => Reflect.parse("async () => true"), SyntaxError); + // Async arrow functions are allowed, but not supported yet + assertThrows(() => Reflect.parse("async () => true"), SyntaxError); -// Async function expressions -assertEq(Reflect.parse("(async function() {})()").body[0].expression.callee.async, true); -assertEq(Reflect.parse("var k = async function() {}").body[0].declarations[0].init.async, true); -assertEq(Reflect.parse("var nmd = async function named() {}").body[0].declarations[0].init.id.name, "named"); + // Async function expressions + assertEq(Reflect.parse("(async function() {})()").body[0].expression.callee.async, true); + assertEq(Reflect.parse("var k = async function() {}").body[0].declarations[0].init.async, true); + assertEq(Reflect.parse("var nmd = async function named() {}").body[0].declarations[0].init.id.name, "named"); -// Awaiting not directly inside an async function is not allowed -assertThrows(() => Reflect.parse("await 4;"), SyntaxError); -assertThrows(() => Reflect.parse("function a() { await 4; }"), SyntaxError); -assertThrows(() => Reflect.parse("function* a() { await 4; }"), SyntaxError); -assertThrows(() => Reflect.parse("async function k() { function a() { await 4; } }"), SyntaxError); + // Awaiting not directly inside an async function is not allowed + assertThrows(() => Reflect.parse("await 4;"), SyntaxError); + assertThrows(() => Reflect.parse("function a() { await 4; }"), SyntaxError); + assertThrows(() => Reflect.parse("function* a() { await 4; }"), SyntaxError); + assertThrows(() => Reflect.parse("async function k() { function a() { await 4; } }"), SyntaxError); -// No line terminator after await is allowed -assertThrows(() => Reflect.parse("async function a() { await\n4; }"), SyntaxError); + // No line terminator after await is allowed + assertThrows(() => Reflect.parse("async function a() { await\n4; }"), SyntaxError); -// Await is not allowed as a default expr. -assertThrows(() => Reflect.parse("async function a(k = await 3) {}"), SyntaxError); -assertThrows(() => Reflect.parse("async function a() { async function b(k = await 3) {} }"), SyntaxError); + // Await is not allowed as a default expr. + assertThrows(() => Reflect.parse("async function a(k = await 3) {}"), SyntaxError); + assertThrows(() => Reflect.parse("async function a() { async function b(k = await 3) {} }"), SyntaxError); -// Await is not legal as an identifier in an async function. -assertThrows(() => Reflect.parse("async function a() { var await = 4; }"), SyntaxError); -assertThrows(() => Reflect.parse("async function a() { return await; }"), SyntaxError); + // Await is not legal as an identifier in an async function. + assertThrows(() => Reflect.parse("async function a() { var await = 4; }"), SyntaxError); + assertThrows(() => Reflect.parse("async function a() { return await; }"), SyntaxError); -// Yield is not allowed in an async function / treated as identifier -assertThrows(() => Reflect.parse("async function a() { yield 3; }"), SyntaxError); + // Yield is not allowed in an async function / treated as identifier + assertThrows(() => Reflect.parse("async function a() { yield 3; }"), SyntaxError); -// Await is still available as an identifier name in strict mode code. -Reflect.parse("function a() { 'use strict'; var await = 3; }"); -Reflect.parse("'use strict'; var await = 3;"); + // Await is still available as an identifier name in strict mode code. + Reflect.parse("function a() { 'use strict'; var await = 3; }"); + Reflect.parse("'use strict'; var await = 3;"); -// Await is treated differently depending on context. Various cases. -Reflect.parse("var await = 3; async function a() { await 4; }"); -Reflect.parse("async function a() { await 4; } var await = 5"); -Reflect.parse("async function a() { function b() { return await; } }") + // Await is treated differently depending on context. Various cases. + Reflect.parse("var await = 3; async function a() { await 4; }"); + Reflect.parse("async function a() { await 4; } var await = 5"); + Reflect.parse("async function a() { function b() { return await; } }") -Reflect.parse("async function a() { var k = { async: 4 } }"); + Reflect.parse("async function a() { var k = { async: 4 } }"); -Reflect.parse("function a() { await: 4 }"); + Reflect.parse("function a() { await: 4 }"); -assertEq(Reflect.parse("async function a() { await 4; }") - .body[0].body.body[0].expression.operator, "await"); + assertEq(Reflect.parse("async function a() { await 4; }") + .body[0].body.body[0].expression.operator, "await"); -assertEq(Reflect.parse("async function a() { async function b() { await 4; } }") - .body[0].body.body[0].body.body[0].expression.operator, "await"); + assertEq(Reflect.parse("async function a() { async function b() { await 4; } }") + .body[0].body.body[0].body.body[0].expression.operator, "await"); -// operator priority test -assertEq(Reflect.parse("async function a() { await 2 + 3; }") - .body[0].body.body[0].expression.left.argument.value, 2); -assertEq(Reflect.parse("async function a() { await 2 + 3; }") - .body[0].body.body[0].expression.left.operator, "await"); -assertEq(Reflect.parse("async function a() { await 2 + 3; }") - .body[0].body.body[0].expression.right.value, 3); + // operator priority test + assertEq(Reflect.parse("async function a() { await 2 + 3; }") + .body[0].body.body[0].expression.left.argument.value, 2); + assertEq(Reflect.parse("async function a() { await 2 + 3; }") + .body[0].body.body[0].expression.left.operator, "await"); + assertEq(Reflect.parse("async function a() { await 2 + 3; }") + .body[0].body.body[0].expression.right.value, 3); -// blocks and other constructions -assertEq(Reflect.parse("{ async function a() { return 2; } }") - .body[0].body[0].async, true); + // blocks and other constructions + assertEq(Reflect.parse("{ async function a() { return 2; } }") + .body[0].body[0].async, true); +} if (typeof reportCompare === "function") reportCompare(true, true); diff --git a/js/src/tests/shell.js b/js/src/tests/shell.js index a2021e90e27b..daf75716d41d 100644 --- a/js/src/tests/shell.js +++ b/js/src/tests/shell.js @@ -872,6 +872,17 @@ function assertThrowsInstanceOf(f, ctor, msg) { throw new Error(fullmsg); }; +function classesEnabled(testCode = "class Foo { constructor() {} }") { + try { + new Function(testCode); + return true; + } catch (e) { + if (!(e instanceof SyntaxError)) + throw e; + return false; + } +} + /* * Some tests need to know if we are in Rhino as opposed to SpiderMonkey */ From 39278371fb73f17308a41326e6e3751b6f1cb8aa Mon Sep 17 00:00:00 2001 From: Eric Faust Date: Mon, 5 Oct 2015 13:24:03 -0700 Subject: [PATCH 037/228] Bug 1185106 - Follow up 2: Fix a non-JS_HAS_ASYNC_FUNCS build warning. (r=me) --- js/src/frontend/Parser.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 9221f99e9bed..6d5ca4984186 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -6804,10 +6804,10 @@ Parser::statement(YieldHandling yieldHandling, bool canHaveDirecti case TOK_NAME: { TokenKind next; - TokenKind nextSameLine = TOK_EOF; #ifdef JS_HAS_ASYNC_FUNCS if (tokenStream.currentName() == context->names().async) { + TokenKind nextSameLine = TOK_EOF; if (!tokenStream.peekTokenSameLine(&nextSameLine)) return null(); if (nextSameLine == TOK_FUNCTION) { @@ -7205,10 +7205,9 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl bool endsExpr; if (tt == TOK_NAME) { - TokenKind nextSameLine = TOK_EOF; - #ifdef JS_HAS_ASYNC_FUNCS if (tokenStream.currentName() == context->names().async) { + TokenKind nextSameLine = TOK_EOF; if (!tokenStream.peekTokenSameLine(&nextSameLine)) return null(); From e19fd45ea51ff59cbb5482b8512e7e338be5c56f Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Tue, 6 Oct 2015 17:28:32 +0200 Subject: [PATCH 038/228] Bug 1205639 - MacroAssembler*::toggledCall: Prevent assertions in oom cases. r=jandem --- js/src/jit/mips32/MacroAssembler-mips32.cpp | 2 +- js/src/jit/x64/Assembler-x64.h | 2 +- js/src/jit/x86/Assembler-x86.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/js/src/jit/mips32/MacroAssembler-mips32.cpp b/js/src/jit/mips32/MacroAssembler-mips32.cpp index d1b6c7319404..f83f8d38790b 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.cpp +++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp @@ -3199,7 +3199,7 @@ MacroAssemblerMIPSCompat::toggledCall(JitCode* target, bool enabled) as_nop(); as_nop(); } - MOZ_ASSERT(nextOffset().getOffset() - offset.offset() == ToggledCallSize(nullptr)); + MOZ_ASSERT_IF(!oom(), nextOffset().getOffset() - offset.offset() == ToggledCallSize(nullptr)); return offset; } diff --git a/js/src/jit/x64/Assembler-x64.h b/js/src/jit/x64/Assembler-x64.h index f6c25975ecc9..6f1b3f859fdb 100644 --- a/js/src/jit/x64/Assembler-x64.h +++ b/js/src/jit/x64/Assembler-x64.h @@ -777,7 +777,7 @@ class Assembler : public AssemblerX86Shared CodeOffsetLabel offset(size()); JmpSrc src = enabled ? masm.call() : masm.cmp_eax(); addPendingJump(src, ImmPtr(target->raw()), Relocation::JITCODE); - MOZ_ASSERT(size() - offset.offset() == ToggledCallSize(nullptr)); + MOZ_ASSERT_IF(!oom(), size() - offset.offset() == ToggledCallSize(nullptr)); return offset; } diff --git a/js/src/jit/x86/Assembler-x86.h b/js/src/jit/x86/Assembler-x86.h index d1acac67e31c..dbabb105b579 100644 --- a/js/src/jit/x86/Assembler-x86.h +++ b/js/src/jit/x86/Assembler-x86.h @@ -470,7 +470,7 @@ class Assembler : public AssemblerX86Shared CodeOffsetLabel offset(size()); JmpSrc src = enabled ? masm.call() : masm.cmp_eax(); addPendingJump(src, ImmPtr(target->raw()), Relocation::JITCODE); - MOZ_ASSERT(size() - offset.offset() == ToggledCallSize(nullptr)); + MOZ_ASSERT_IF(!oom(), size() - offset.offset() == ToggledCallSize(nullptr)); return offset; } From c05e2b4f001611fbcc807b135959ef3e54bd03d9 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Tue, 6 Oct 2015 08:49:21 -0700 Subject: [PATCH 039/228] Backed out 6 changesets (bug 1185106) for SM bustage CLOSED TREE Backed out changeset 8453ae71b30d (bug 1185106) Backed out changeset 446ea07800c9 (bug 1185106) Backed out changeset a3c1f65f0dff (bug 1185106) Backed out changeset 5174ef291f0c (bug 1185106) Backed out changeset 8073e7c4cf94 (bug 1185106) Backed out changeset 3afd56565e23 (bug 1185106) --- js/src/Makefile.in | 2 - js/src/asmjs/AsmJSValidate.cpp | 2 +- js/src/builtin/AsyncFunctions.js | 46 ---- js/src/builtin/Promise.cpp | 141 ---------- js/src/builtin/Promise.h | 29 --- js/src/builtin/Promise.js | 241 ------------------ js/src/builtin/ReflectParse.cpp | 45 +--- js/src/builtin/SelfHostingDefines.h | 9 - js/src/frontend/BytecodeCompiler.cpp | 6 +- js/src/frontend/BytecodeEmitter.cpp | 59 +---- js/src/frontend/BytecodeEmitter.h | 2 - js/src/frontend/FoldConstants.cpp | 2 - js/src/frontend/FullParseHandler.h | 5 - js/src/frontend/NameFunctions.cpp | 1 - js/src/frontend/ParseNode.cpp | 6 +- js/src/frontend/ParseNode.h | 1 - js/src/frontend/Parser.cpp | 222 +++------------- js/src/frontend/Parser.h | 39 +-- js/src/frontend/SharedContext.h | 7 +- js/src/frontend/SyntaxParseHandler.h | 3 +- js/src/frontend/TokenKind.h | 2 - js/src/frontend/TokenStream.cpp | 5 - js/src/frontend/TokenStream.h | 10 - js/src/jit-test/lib/class.js | 3 +- js/src/jit/BaselineCompiler.cpp | 8 +- js/src/jit/CodeGenerator.cpp | 3 +- js/src/jit/IonBuilder.cpp | 8 +- js/src/jit/Lowering.cpp | 6 +- js/src/jit/MIR.h | 19 +- js/src/jit/shared/LIR-shared.h | 12 +- js/src/js.msg | 12 - js/src/jsfun.cpp | 7 +- js/src/jsfun.h | 13 - js/src/jsprototypes.h | 7 - js/src/jsscript.cpp | 2 - js/src/jsscript.h | 18 +- js/src/jsversion.h | 3 - js/src/moz.build | 1 - js/src/shell/js.cpp | 71 ------ js/src/tests/ecma_6/Promise/promise.js | 45 ---- js/src/tests/ecma_6/Promise/security.js | 12 - js/src/tests/ecma_6/Promise/shell.js | 23 -- js/src/tests/ecma_6/shell.js | 11 + js/src/tests/ecma_7/AsyncFunctions/1.1.1.js | 20 -- js/src/tests/ecma_7/AsyncFunctions/1.1.2.js | 20 -- js/src/tests/ecma_7/AsyncFunctions/methods.js | 65 ----- .../tests/ecma_7/AsyncFunctions/semantics.js | 177 ------------- js/src/tests/ecma_7/AsyncFunctions/shell.js | 36 --- .../ecma_7/AsyncFunctions/syntax-modules.js | 10 - js/src/tests/ecma_7/AsyncFunctions/syntax.js | 87 ------- js/src/tests/shell.js | 11 - js/src/vm/CommonPropertyNames.h | 2 - js/src/vm/GlobalObject.cpp | 5 - js/src/vm/GlobalObject.h | 6 - js/src/vm/Interpreter.cpp | 15 +- js/src/vm/Keywords.h | 1 - js/src/vm/Opcodes.h | 3 +- js/src/vm/ScopeObject.cpp | 7 +- js/src/vm/SelfHosting.cpp | 68 ----- js/src/vm/Xdr.h | 4 +- 60 files changed, 131 insertions(+), 1575 deletions(-) delete mode 100644 js/src/builtin/AsyncFunctions.js delete mode 100644 js/src/builtin/Promise.cpp delete mode 100644 js/src/builtin/Promise.h delete mode 100644 js/src/builtin/Promise.js delete mode 100644 js/src/tests/ecma_6/Promise/promise.js delete mode 100644 js/src/tests/ecma_6/Promise/security.js delete mode 100644 js/src/tests/ecma_6/Promise/shell.js delete mode 100644 js/src/tests/ecma_7/AsyncFunctions/1.1.1.js delete mode 100644 js/src/tests/ecma_7/AsyncFunctions/1.1.2.js delete mode 100644 js/src/tests/ecma_7/AsyncFunctions/methods.js delete mode 100644 js/src/tests/ecma_7/AsyncFunctions/semantics.js delete mode 100644 js/src/tests/ecma_7/AsyncFunctions/shell.js delete mode 100644 js/src/tests/ecma_7/AsyncFunctions/syntax-modules.js delete mode 100644 js/src/tests/ecma_7/AsyncFunctions/syntax.js diff --git a/js/src/Makefile.in b/js/src/Makefile.in index 8d45c370dc22..04ca77dc5eb1 100644 --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -284,7 +284,6 @@ selfhosting:: selfhosted.out.h selfhosting_srcs := \ $(srcdir)/builtin/Utilities.js \ $(srcdir)/builtin/Array.js \ - $(srcdir)/builtin/AsyncFunctions.js \ $(srcdir)/builtin/Date.js \ $(srcdir)/builtin/Error.js \ $(srcdir)/builtin/Generator.js \ @@ -295,7 +294,6 @@ selfhosting_srcs := \ $(srcdir)/builtin/Module.js \ $(srcdir)/builtin/Number.js \ $(srcdir)/builtin/Object.js \ - $(srcdir)/builtin/Promise.js \ $(srcdir)/builtin/Reflect.js \ $(srcdir)/builtin/RegExp.js \ $(srcdir)/builtin/String.js \ diff --git a/js/src/asmjs/AsmJSValidate.cpp b/js/src/asmjs/AsmJSValidate.cpp index cffd4f4e1a12..55ffa08cbe20 100644 --- a/js/src/asmjs/AsmJSValidate.cpp +++ b/js/src/asmjs/AsmJSValidate.cpp @@ -6348,7 +6348,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut) AsmJSParseContext* outerpc = m.parser().pc; Directives directives(outerpc); - FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, outerpc, directives, NotGenerator, SyncFunction); + FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, outerpc, directives, NotGenerator); if (!funbox) return false; diff --git a/js/src/builtin/AsyncFunctions.js b/js/src/builtin/AsyncFunctions.js deleted file mode 100644 index 0f918d3a9f98..000000000000 --- a/js/src/builtin/AsyncFunctions.js +++ /dev/null @@ -1,46 +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/. */ - -function AsyncFunction_wrap(genFunction) { - var wrapper = function() { - // The try block is required to handle throws in default arguments properly. - try { - return AsyncFunction_start(callFunction(std_Function_apply, genFunction, this, arguments)); - } catch (e) { - return Promise_reject(e); - } - }; - SetFunctionExtendedSlot(genFunction, 1, wrapper); - var name = GetFunName(genFunction); - if (typeof name !== 'undefined') - SetFunName(wrapper, name); - return wrapper; -} - -function AsyncFunction_start(generator) { - return AsyncFunction_resume(generator, undefined, generator.next); -} - -function AsyncFunction_resume(gen, v, method) { - let result; - try { - // get back into async function, run to next await point - result = callFunction(method, gen, v); - } catch (exc) { - // The async function itself failed. - return Promise_reject(exc); - } - - if (result.done) - return Promise_resolve(result.value); - - // If we get here, `await` occurred. `gen` is paused at a yield point. - return callFunction(Promise_then, - Promise_resolve(result.value), - function(val) { - return AsyncFunction_resume(gen, val, gen.next); - }, function (err) { - return AsyncFunction_resume(gen, err, gen.throw); - }); -} diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp deleted file mode 100644 index cf3f25fc3424..000000000000 --- a/js/src/builtin/Promise.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * 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/. */ - -#include "builtin/Promise.h" - -#include "jscntxt.h" - -#include "builtin/SelfHostingDefines.h" - -#include "jsobjinlines.h" - -using namespace js; - -static const JSFunctionSpec promise_methods[] = { - JS_SELF_HOSTED_FN("catch", "Promise_catch", 1, 0), - JS_SELF_HOSTED_FN("then", "Promise_then", 2, 0), - JS_FS_END -}; - -static const JSFunctionSpec promise_static_methods[] = { - JS_SELF_HOSTED_FN("all", "Promise_all", 1, 0), - JS_SELF_HOSTED_FN("race", "Promise_race", 1, 0), - JS_SELF_HOSTED_FN("reject", "Promise_reject", 1, 0), - JS_SELF_HOSTED_FN("resolve", "Promise_resolve", 1, 0), - JS_FS_END -}; - -namespace js { - -bool -PromiseConstructor(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - - if (args.length() == 0) { - JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED, - "ShellPromise.constructor", "0", "s"); - return false; - } - - HandleValue fn = args.get(0); - - if (!IsCallable(fn)) { - JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_CALLABLE, - "Argument 1 of ShellPromise.constructor"); - return false; - } - - RootedObject promise(cx, NewBuiltinClassInstance(cx, &ShellPromiseObject::class_)); - if (!promise) - return false; - - JS_SetReservedSlot(promise, PROMISE_STATE_SLOT, NumberValue(PROMISE_STATE_PENDING)); - JS_SetReservedSlot(promise, PROMISE_VALUE_SLOT, NullValue()); - JS_SetReservedSlot(promise, PROMISE_DEFERREDS_SLOT, NullValue()); - - RootedValue initRval(cx); - JS::AutoValueVector argValues(cx); - argValues.append(ObjectValue(*promise)); - argValues.append(fn); - HandleValueArray arr(argValues); - - JSAtom* promiseInitAtom; - if (!(promiseInitAtom = Atomize(cx, "Promise_init", 12))) - return false; - - RootedPropertyName name(cx, promiseInitAtom->asPropertyName()); - RootedValue selfHostedFun(cx); - - if (!GlobalObject::getIntrinsicValue(cx, cx->global(), name, &selfHostedFun)) - return false; - - if (!JS_CallFunctionValue(cx, promise, selfHostedFun, arr, &initRval)) - return false; - - args.rval().setObject(*promise); - - return true; -} - -} - -static JSObject* -CreatePromisePrototype(JSContext* cx, JSProtoKey key) -{ - return cx->global()->createBlankPrototype(cx, &ShellPromiseObject::protoClass_); -} - -const Class ShellPromiseObject::class_ = { - "ShellPromise", - JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_ShellPromise), - nullptr, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - nullptr, /* enumerate */ - nullptr, /* resolve */ - nullptr, /* mayResolve */ - nullptr, /* finalize */ - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - nullptr, /* trace */ - { - GenericCreateConstructor, - CreatePromisePrototype, - promise_static_methods, - nullptr, - promise_methods - } -}; - -const Class ShellPromiseObject::protoClass_ = { - "ShellPromise", - JSCLASS_HAS_CACHED_PROTO(JSProto_ShellPromise), - nullptr, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - nullptr, /* enumerate */ - nullptr, /* resolve */ - nullptr, /* mayResolve */ - nullptr, /* finalize */ - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - nullptr, /* trace */ - { - DELEGATED_CLASSSPEC(&ShellPromiseObject::class_.spec), - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - ClassSpec::IsDelegated - } -}; diff --git a/js/src/builtin/Promise.h b/js/src/builtin/Promise.h deleted file mode 100644 index 53f1399416da..000000000000 --- a/js/src/builtin/Promise.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * 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/. */ - -#ifndef builtin_Promise_h -#define builtin_Promise_h - -#include "vm/NativeObject.h" - -namespace js { - -class AutoSetNewObjectMetadata; - -class ShellPromiseObject : public NativeObject -{ - public: - static const unsigned RESERVED_SLOTS = 3; - static const Class class_; - static const Class protoClass_; -}; - -bool -PromiseConstructor(JSContext* cx, unsigned argc, Value* vp); - -} // namespace js - -#endif /* builtin_Promise_h */ diff --git a/js/src/builtin/Promise.js b/js/src/builtin/Promise.js deleted file mode 100644 index 65fc9dd1295a..000000000000 --- a/js/src/builtin/Promise.js +++ /dev/null @@ -1,241 +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/. */ - -/** - * This implementation is by no means complete and is using a polyfill. - * In particular, it doesn't fully comply to ES6 Promises spec. - * The list of incompatibilities may not be complete and includes: - * - * - no [Symbol.species] implementation - * - implementation is not really async at all, but all is executed - * in correct order - * - Promise.race is not implemented (not necessary for async/await) - * - Promise.all implementation currently only handles arrays, no other - * iterables. - */ - - /** - * This polyfill implements the Promise specification in the following way: - * At first, Promise is initialized with the intrinsic Promise constructor, - * with its initialization completed by calling Promise_init. The goal is to - * completely resolve/reject the promise. There are certain helper functions: - * - resolveOneStep() executes "one step" of the promise - which means - * getting either the final value or next promise towards complete execution. - * - resolveCompletely() executes the entire promise, which merely means - * resolving one step at a time, until the final step no longer resolves - * to a promise (which means either resolving to a value or rejecting). - * - * Once resolution is finished, resolveCompletely() is called in order to - * update state of the promise. It also spawns callbacks that may have been - * deferred with a then() - they are NOT normally taken into consideration, - * because resolveCompletely() just runs one path. - */ - -/** - * Below is a simple simulation of an event loop. Events enqueued using - * this setTimeout implementation must be manually triggered by calling - * runEvents(). - */ -var eventQueue = new List(); - -function runEvents() { - while (eventQueue.length > 0) { - var evt = callFunction(std_Array_pop, eventQueue); - evt(); - } -} - -function setTimeout(cb, interval) { - if (!IsCallable(cb)) - ThrowTypeError(JSMSG_NOT_CALLABLE, "Argument 0"); - if (interval !== 0) - ThrowTypeError(JSMSG_SETTIMEOUT_INTERVAL_NONZERO); - callFunction(std_Array_push, eventQueue, cb); -} - -function Handler(onFulfilled, onRejected, resolve, reject) { - this.onFulfilled = IsCallable(onFulfilled) ? onFulfilled : null; - this.onRejected = IsCallable(onRejected) ? onRejected : null; - this.resolve = resolve; - this.reject = reject; -} - -MakeConstructible(Handler, std_Object_create(null)); - -function Promise_setState(promise, state) { - UnsafeSetReservedSlot(promise, PROMISE_STATE_SLOT, state); -} - -function Promise_getState(promise) { - return UnsafeGetReservedSlot(promise, PROMISE_STATE_SLOT); -} - -function Promise_setDeferreds(promise, deferreds) { - UnsafeSetReservedSlot(promise, PROMISE_DEFERREDS_SLOT, deferreds); -} - -function Promise_getDeferreds(promise) { - return UnsafeGetReservedSlot(promise, PROMISE_DEFERREDS_SLOT); -} - -function Promise_setValue(promise, value) { - UnsafeSetReservedSlot(promise, PROMISE_VALUE_SLOT, value); -} - -function Promise_getValue(promise) { - return UnsafeGetReservedSlot(promise, PROMISE_VALUE_SLOT); -} - -function Promise_init(promise, fn) { - Promise_setDeferreds(promise, new List()); - resolveOneStep(fn, - function(value) { resolveCompletely(promise, value); }, - function(reason) { reject(promise, reason); }); -} - -function Promise_isThenable(valueOrPromise) { - if (valueOrPromise && (typeof valueOrPromise === 'object' || IsCallable(valueOrPromise))) { - var then = valueOrPromise.then; - if (IsCallable(then)) - return true; - } - return false; -} - -function Promise_all(promises) { - var length = promises.length; - var results = []; - return NewPromise(function (resolve, reject) { - if (length === 0) - return resolve([]); - var remaining = length; - function resolveChain(index, valueOrPromise) { - try { - if (Promise_isThenable(valueOrPromise)) { - callFunction(valueOrPromise.then, valueOrPromise, - function (valueOrPromise) { resolveChain(index, valueOrPromise); }, - reject); - } else { - _DefineDataProperty(results, index, valueOrPromise); - if (--remaining === 0) - resolve(results); - } - } catch (ex) { - reject(ex); - } - } - for (var i = 0; i < length; i++) - resolveChain(i, promises[i]); - }); -} - -function Promise_race(values) { - ThrowTypeError(JSMSG_NOT_IMPLEMENTED, "Promise.race"); -} - -function Promise_reject(value) { - return NewPromise(function (resolve, reject) { - reject(value); - }); -} - -function Promise_resolve(value) { - if (value && typeof value === 'object' && IsPromise(value)) - return value; - - return NewPromise(function (resolve) { - resolve(value); - }); -} - -function Promise_catch(onRejected) { - return callFunction(Promise_then, this, undefined, onRejected); -} - -function asap(cb) { - setTimeout(cb, 0); -} - -function deferOrExecute(promise, deferred) { - if (Promise_getState(promise) === PROMISE_STATE_PENDING) { - Promise_getDeferreds(promise).push(deferred); - return; - } - - asap(function() { - var cb = Promise_getState(promise) === PROMISE_STATE_RESOLVED ? - deferred.onFulfilled : deferred.onRejected; - if (cb === null) { - var value = Promise_getValue(promise); - (Promise_getState(promise) === PROMISE_STATE_RESOLVED ? deferred.resolve : deferred.reject)(value); - return; - } - var returnValue; - try { - returnValue = cb(Promise_getValue(promise)); - } catch (e) { - deferred.reject(e); - return; - } - deferred.resolve(returnValue); - }); -} - -function resolveOneStep(fn, onFulfilled, onRejected) { - var done = false; - var callOnce = function(cb) { - return function(value) { - if (done) return; - done = true; - cb(value); - }; - }; - - try { - fn(callOnce(onFulfilled), callOnce(onRejected)); - } catch (ex) { - callOnce(onRejected)(ex); - } -} - -function resolveCompletely(promise, valueOrPromise) { - try { - // FIXME this is probably not a type error - if (valueOrPromise === promise) - ThrowTypeError(JSMSG_PROMISE_RESOLVED_WITH_ITSELF); - - if (Promise_isThenable(valueOrPromise)) { - resolveOneStep(function(resolve, reject) { valueOrPromise.then(resolve, reject); }, - function(value) { resolveCompletely(promise, value); }, - function(value) { reject(promise, value); }); - } - else - callFunction(resolvingFinished, promise, PROMISE_STATE_RESOLVED, valueOrPromise); - } catch (ex) { - callFunction(reject, promise, ex); - } -} - -function reject(promise, reason) { - callFunction(resolvingFinished, promise, PROMISE_STATE_REJECTED, reason); -} - -function resolvingFinished(state, newValue) { - Promise_setState(this, state); - Promise_setValue(this, newValue); - var deferreds = Promise_getDeferreds(this); - for (var i = 0, len = deferreds.length; i < len; i++) - deferOrExecute(this, deferreds[i]); - Promise_setDeferreds(this, null); -} - -function Promise_then(onFulfilled, onRejected) { - var promise = this; - var newPromise = NewPromise(function(resolve, reject) { - deferOrExecute(promise, - new Handler(onFulfilled, onRejected, resolve, reject)); - }); - runEvents(); - return newPromise; -} diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp index 82da131a8414..8c30db7c3996 100644 --- a/js/src/builtin/ReflectParse.cpp +++ b/js/src/builtin/ReflectParse.cpp @@ -91,7 +91,6 @@ enum UnaryOperator { UNOP_BITNOT, UNOP_TYPEOF, UNOP_VOID, - UNOP_AWAIT, UNOP_LIMIT }; @@ -161,8 +160,7 @@ static const char* const unopNames[] = { "!", /* UNOP_NOT */ "~", /* UNOP_BITNOT */ "typeof", /* UNOP_TYPEOF */ - "void", /* UNOP_VOID */ - "await" /* UNOP_AWAIT */ + "void" /* UNOP_VOID */ }; static const char* const nodeTypeNames[] = { @@ -562,29 +560,6 @@ class NodeBuilder setResult(node, dst); } - bool newNode(ASTType type, TokenPos* pos, - const char* childName1, HandleValue child1, - const char* childName2, HandleValue child2, - const char* childName3, HandleValue child3, - const char* childName4, HandleValue child4, - const char* childName5, HandleValue child5, - const char* childName6, HandleValue child6, - const char* childName7, HandleValue child7, - const char* childName8, HandleValue child8, - MutableHandleValue dst) { - RootedObject node(cx); - return newNode(type, pos, &node) && - setProperty(node, childName1, child1) && - setProperty(node, childName2, child2) && - setProperty(node, childName3, child3) && - setProperty(node, childName4, child4) && - setProperty(node, childName5, child5) && - setProperty(node, childName6, child6) && - setProperty(node, childName7, child7) && - setProperty(node, childName8, child8) && - setResult(node, dst); - } - bool listNode(ASTType type, const char* propName, NodeVector& elts, TokenPos* pos, MutableHandleValue dst) { RootedValue array(cx); @@ -645,8 +620,8 @@ class NodeBuilder bool function(ASTType type, TokenPos* pos, HandleValue id, NodeVector& args, NodeVector& defaults, - HandleValue body, HandleValue rest, bool isGenerator, bool isAsync, - bool isExpression, MutableHandleValue dst); + HandleValue body, HandleValue rest, bool isGenerator, bool isExpression, + MutableHandleValue dst); bool variableDeclarator(HandleValue id, HandleValue init, TokenPos* pos, MutableHandleValue dst); @@ -1782,7 +1757,7 @@ bool NodeBuilder::function(ASTType type, TokenPos* pos, HandleValue id, NodeVector& args, NodeVector& defaults, HandleValue body, HandleValue rest, - bool isGenerator, bool isAsync, bool isExpression, + bool isGenerator, bool isExpression, MutableHandleValue dst) { RootedValue array(cx), defarray(cx); @@ -1792,7 +1767,6 @@ NodeBuilder::function(ASTType type, TokenPos* pos, return false; RootedValue isGeneratorVal(cx, BooleanValue(isGenerator)); - RootedValue isAsyncVal(cx, BooleanValue(isAsync)); RootedValue isExpressionVal(cx, BooleanValue(isExpression)); RootedValue cb(cx, callbacks[type]); @@ -1807,7 +1781,6 @@ NodeBuilder::function(ASTType type, TokenPos* pos, "body", body, "rest", rest, "generator", isGeneratorVal, - "async", isAsyncVal, "expression", isExpressionVal, dst); } @@ -2053,9 +2026,6 @@ ASTSerializer::unop(ParseNodeKind kind, JSOp op) if (kind == PNK_TYPEOFNAME || kind == PNK_TYPEOFEXPR) return UNOP_TYPEOF; - if (kind == PNK_AWAIT) - return UNOP_AWAIT; - switch (op) { case JSOP_NEG: return UNOP_NEG; @@ -3114,7 +3084,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) return leftAssociate(pn, dst); case PNK_POW: - return rightAssociate(pn, dst); + return rightAssociate(pn, dst); case PNK_DELETENAME: case PNK_DELETEPROP: @@ -3126,7 +3096,6 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) case PNK_NOT: case PNK_BITNOT: case PNK_POS: - case PNK_AWAIT: case PNK_NEG: { MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos)); @@ -3596,7 +3565,7 @@ ASTSerializer::function(ParseNode* pn, ASTType type, MutableHandleValue dst) // FIXME: Provide more information (legacy generator vs star generator). bool isGenerator = pn->pn_funbox->isGenerator(); - bool isAsync = pn->pn_funbox->isAsync(); + bool isExpression = #if JS_HAS_EXPR_CLOSURES func->isExprBody(); @@ -3619,7 +3588,7 @@ ASTSerializer::function(ParseNode* pn, ASTType type, MutableHandleValue dst) rest.setNull(); return functionArgsAndBody(pn->pn_body, args, defaults, &body, &rest) && builder.function(type, &pn->pn_pos, id, args, defaults, body, - rest, isGenerator, isAsync, isExpression, dst); + rest, isGenerator, isExpression, dst); } bool diff --git a/js/src/builtin/SelfHostingDefines.h b/js/src/builtin/SelfHostingDefines.h index 290319d92364..e11fc82a39a8 100644 --- a/js/src/builtin/SelfHostingDefines.h +++ b/js/src/builtin/SelfHostingDefines.h @@ -33,15 +33,6 @@ // Stores the private WeakMap slot used for WeakSets #define WEAKSET_MAP_SLOT 0 -// Slots for use with promises implementation. -#define PROMISE_STATE_SLOT 0 -#define PROMISE_VALUE_SLOT 1 -#define PROMISE_DEFERREDS_SLOT 2 - -#define PROMISE_STATE_PENDING 0 -#define PROMISE_STATE_RESOLVED 1 -#define PROMISE_STATE_REJECTED 2 - #define ITERATOR_SLOT_TARGET 0 // Used for collection iterators. #define ITERATOR_SLOT_RANGE 1 diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index 28f55574cdb4..0e56102dd93d 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -314,7 +314,7 @@ BytecodeCompiler::saveCallerFun(HandleScript evalCaller, MOZ_ASSERT_IF(fun->strict(), options.strictOption); Directives directives(/* strict = */ options.strictOption); ObjectBox* funbox = parser->newFunctionBox(/* fn = */ nullptr, fun, &parseContext, - directives, fun->generatorKind(), fun->asyncKind()); + directives, fun->generatorKind()); if (!funbox) return false; @@ -705,7 +705,7 @@ BytecodeCompiler::compileFunctionBody(MutableHandleFunction fun, ParseNode* fn; do { Directives newDirectives = directives; - fn = parser->standaloneFunctionBody(fun, formals, generatorKind, SyncFunction, directives, + fn = parser->standaloneFunctionBody(fun, formals, generatorKind, directives, &newDirectives, enclosingStaticScope); if (!fn && !handleParseFailure(newDirectives)) return false; @@ -865,7 +865,7 @@ frontend::CompileLazyFunction(JSContext* cx, Handle lazy, const cha Rooted fun(cx, lazy->functionNonDelazifying()); MOZ_ASSERT(!lazy->isLegacyGenerator()); - ParseNode* pn = parser.standaloneLazyFunction(fun, lazy->strict(), lazy->generatorKind(), lazy->asyncKind()); + ParseNode* pn = parser.standaloneLazyFunction(fun, lazy->strict(), lazy->generatorKind()); if (!pn) return false; diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index e53ea56fb1c3..825e5f4a0ed1 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -240,6 +240,7 @@ bool BytecodeEmitter::emit1(JSOp op) { MOZ_ASSERT(checkStrictOrSloppy(op)); + ptrdiff_t offset; if (!emitCheck(1, &offset)) return false; @@ -2011,7 +2012,6 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) case PNK_YIELD_STAR: case PNK_YIELD: - case PNK_AWAIT: MOZ_ASSERT(pn->isArity(PN_BINARY)); *answer = true; return true; @@ -5857,16 +5857,6 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto) MOZ_ASSERT(pn->getOp() == JSOP_LAMBDA); pn->setOp(JSOP_FUNWITHPROTO); } - - if (funbox->isAsync()) - return emitAsyncWrapper(index, funbox->needsHomeObject()); - - if (pn->getOp() == JSOP_DEFFUN) { - if (!emitIndex32(JSOP_LAMBDA, index)) - return false; - return emit1(JSOP_DEFFUN); - } - return emitIndex32(pn->getOp(), index); } @@ -5886,14 +5876,7 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto) MOZ_ASSERT(pn->getOp() == JSOP_NOP); MOZ_ASSERT(atBodyLevel()); switchToPrologue(); - if (funbox->isAsync()) { - if (!emitAsyncWrapper(index, fun->isMethod())) - return false; - } else { - if (!emitIndex32(JSOP_LAMBDA, index)) - return false; - } - if (!emit1(JSOP_DEFFUN)) + if (!emitIndex32(JSOP_DEFFUN, index)) return false; if (!updateSourceCoordNotes(pn->pn_pos.begin)) return false; @@ -5907,11 +5890,7 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto) bi->kind() == Binding::ARGUMENT); MOZ_ASSERT(bi.argOrLocalIndex() < JS_BIT(20)); #endif - if (funbox->isAsync()) { - if (!emitAsyncWrapper(index, false)) - return false; - } - else if (!emitIndexOp(JSOP_LAMBDA, index)) + if (!emitIndexOp(JSOP_LAMBDA, index)) return false; MOZ_ASSERT(pn->getOp() == JSOP_GETLOCAL || pn->getOp() == JSOP_GETARG); JSOp setOp = pn->getOp() == JSOP_GETLOCAL ? JSOP_SETLOCAL : JSOP_SETARG; @@ -5924,30 +5903,6 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto) return true; } -bool -BytecodeEmitter::emitAsyncWrapper(unsigned index, bool needsHomeObject) { - JSAtom* atom = Atomize(cx, "AsyncFunction_wrap", 18); - if (!atom) - return false; - /* TODO Comment */ - if (needsHomeObject && !emitIndex32(JSOP_LAMBDA, index)) - return false; - if (!emitAtomOp(atom, JSOP_GETINTRINSIC)) - return false; - if (!emit1(JSOP_UNDEFINED)) - return false; - if (needsHomeObject) { - if (!emitDupAt(2)) - return false; - } else { - if (!emitIndex32(JSOP_LAMBDA, index)) - return false; - } - if (!emitCall(JSOP_CALL, 1)) - return false; - return true; -} - bool BytecodeEmitter::emitDo(ParseNode* pn) { @@ -7114,12 +7069,7 @@ BytecodeEmitter::emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp, propdef->pn_right->pn_funbox->needsHomeObject()) { MOZ_ASSERT(propdef->pn_right->pn_funbox->function()->allowSuperProperty()); - bool isAsync = propdef->pn_right->pn_funbox->isAsync(); - if (isAsync && !emit1(JSOP_SWAP)) - return false; - if (!emit2(JSOP_INITHOMEOBJECT, isIndex + isAsync)) - return false; - if (isAsync && !emit1(JSOP_POP)) + if (!emit2(JSOP_INITHOMEOBJECT, isIndex)) return false; } @@ -7738,7 +7688,6 @@ BytecodeEmitter::emitTree(ParseNode* pn) break; case PNK_YIELD: - case PNK_AWAIT: ok = emitYield(pn); break; diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index 25afd64df7a2..44fe9cb06461 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -482,8 +482,6 @@ struct BytecodeEmitter bool emitPropOp(ParseNode* pn, JSOp op); bool emitPropIncDec(ParseNode* pn); - bool emitAsyncWrapper(unsigned index, bool isMethod); - bool emitComputedPropertyName(ParseNode* computedPropName); // Emit bytecode to put operands for a JSOP_GETELEM/CALLELEM/SETELEM/DELELEM diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp index 6e523efa7a18..003ed0b58334 100644 --- a/js/src/frontend/FoldConstants.cpp +++ b/js/src/frontend/FoldConstants.cpp @@ -329,7 +329,6 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result) case PNK_CONDITIONAL: case PNK_TYPEOFNAME: case PNK_TYPEOFEXPR: - case PNK_AWAIT: case PNK_VOID: case PNK_NOT: case PNK_BITNOT: @@ -1854,7 +1853,6 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser& parser, bo return Fold(cx, &pn->pn_left, parser, inGenexpLambda); case PNK_YIELD: - case PNK_AWAIT: MOZ_ASSERT(pn->isArity(PN_BINARY)); MOZ_ASSERT((pn->pn_right->isKind(PNK_NAME) && !pn->pn_right->isAssigned()) || (pn->pn_right->isKind(PNK_ASSIGN) && diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index 11d52018b6a4..db069cdfd490 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -436,11 +436,6 @@ class FullParseHandler return new_(PNK_YIELD, op, pos, value, gen); } - ParseNode* newAwaitExpression(uint32_t begin, ParseNode* value, ParseNode* gen) { - TokenPos pos(begin, value ? value->pn_pos.end : begin + 1); - return new_(PNK_AWAIT, JSOP_YIELD, pos, value, gen); - } - ParseNode* newYieldStarExpression(uint32_t begin, ParseNode* value, ParseNode* gen) { TokenPos pos(begin, value->pn_pos.end); return new_(PNK_YIELD_STAR, JSOP_NOP, pos, value, gen); diff --git a/js/src/frontend/NameFunctions.cpp b/js/src/frontend/NameFunctions.cpp index 64d0c3acd53f..9c5fae0b0839 100644 --- a/js/src/frontend/NameFunctions.cpp +++ b/js/src/frontend/NameFunctions.cpp @@ -488,7 +488,6 @@ class NameResolver break; case PNK_YIELD: - case PNK_AWAIT: MOZ_ASSERT(cur->isArity(PN_BINARY)); if (cur->pn_left) { if (!resolve(cur->pn_left, prefix)) diff --git a/js/src/frontend/ParseNode.cpp b/js/src/frontend/ParseNode.cpp index a90c9daa0bc4..4ab4aeff20f0 100644 --- a/js/src/frontend/ParseNode.cpp +++ b/js/src/frontend/ParseNode.cpp @@ -324,8 +324,7 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack) // variable, or an assignment of a PNK_GENERATOR node to the '.generator' // local, for a synthesized, prepended initial yield. Yum! case PNK_YIELD_STAR: - case PNK_YIELD: - case PNK_AWAIT: { + case PNK_YIELD: { MOZ_ASSERT(pn->isArity(PN_BINARY)); MOZ_ASSERT(pn->pn_right); MOZ_ASSERT(pn->pn_right->isKind(PNK_NAME) || @@ -702,8 +701,7 @@ Parser::cloneParseTree(ParseNode* opn) RootedFunction fun(context, opn->pn_funbox->function()); NULLCHECK(pn->pn_funbox = newFunctionBox(pn, fun, pc, Directives(/* strict = */ opn->pn_funbox->strict()), - opn->pn_funbox->generatorKind(), - opn->pn_funbox->asyncKind())); + opn->pn_funbox->generatorKind())); NULLCHECK(pn->pn_body = cloneParseTree(opn->pn_body)); pn->pn_scopecoord = opn->pn_scopecoord; pn->pn_dflags = opn->pn_dflags; diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index 5d3e7f00ed14..b54f8accf933 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -183,7 +183,6 @@ class PackedScopeCoordinate F(VOID) \ F(NOT) \ F(BITNOT) \ - F(AWAIT) \ \ /* \ * Binary operators. \ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 6d5ca4984186..38f18d367c78 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -645,8 +645,7 @@ Parser::newObjectBox(JSObject* obj) template FunctionBox::FunctionBox(ExclusiveContext* cx, ObjectBox* traceListHead, JSFunction* fun, JSObject* enclosingStaticScope, ParseContext* outerpc, - Directives directives, bool extraWarnings, GeneratorKind generatorKind, - FunctionAsyncKind asyncKind) + Directives directives, bool extraWarnings, GeneratorKind generatorKind) : ObjectBox(fun, traceListHead), SharedContext(cx, directives, extraWarnings), bindings(), @@ -665,8 +664,7 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, ObjectBox* traceListHead, JSFunct usesArguments(false), usesApply(false), usesThis(false), - funCxFlags(), - _asyncKind(asyncKind) + funCxFlags() { // Functions created at parse time may be set singleton after parsing and // baked into JIT code, so they must be allocated tenured. They are held by @@ -680,7 +678,6 @@ Parser::newFunctionBox(Node fn, JSFunction* fun, ParseContext* outerpc, Directives inheritedDirectives, GeneratorKind generatorKind, - FunctionAsyncKind asyncKind, JSObject* enclosingStaticScope) { MOZ_ASSERT_IF(outerpc, enclosingStaticScope == outerpc->innermostStaticScope()); @@ -696,7 +693,7 @@ Parser::newFunctionBox(Node fn, JSFunction* fun, FunctionBox* funbox = alloc.new_(context, traceListHead, fun, enclosingStaticScope, outerpc, inheritedDirectives, options().extraWarningsOption, - generatorKind, asyncKind); + generatorKind); if (!funbox) { ReportOutOfMemory(context); return nullptr; @@ -839,9 +836,7 @@ Parser::checkStrictBinding(PropertyName* name, Node pn) if (!pc->sc->needStrictChecks()) return true; - if (name == context->names().eval || name == context->names().arguments || - (IsKeyword(name) && name != context->names().await)) - { + if (name == context->names().eval || name == context->names().arguments || IsKeyword(name)) { JSAutoByteString bytes; if (!AtomToPrintableString(context, name, &bytes)) return false; @@ -871,10 +866,7 @@ Parser::standaloneModule(HandleModuleObject module) if (!modulepc.init(*this)) return null(); - bool awaitIsKeyword = tokenStream.getAwaitIsKeyword(); - tokenStream.setAwaitIsKeyword(true); ParseNode* pn = statements(YieldIsKeyword); - tokenStream.setAwaitIsKeyword(awaitIsKeyword); if (!pn) return null(); @@ -949,7 +941,6 @@ ParseNode* Parser::standaloneFunctionBody(HandleFunction fun, Handle formals, GeneratorKind generatorKind, - FunctionAsyncKind asyncKind, Directives inheritedDirectives, Directives* newDirectives, HandleObject enclosingStaticScope) @@ -966,7 +957,7 @@ Parser::standaloneFunctionBody(HandleFunction fun, fn->pn_body = argsbody; FunctionBox* funbox = newFunctionBox(fn, fun, inheritedDirectives, generatorKind, - asyncKind, enclosingStaticScope); + enclosingStaticScope); if (!funbox) return null(); funbox->length = fun->nargs() - fun->hasRest(); @@ -1415,8 +1406,7 @@ struct BindData template JSFunction* Parser::newFunction(HandleAtom atom, FunctionSyntaxKind kind, - GeneratorKind generatorKind, FunctionAsyncKind asyncKind, - HandleObject proto) + GeneratorKind generatorKind, HandleObject proto) { MOZ_ASSERT_IF(kind == Statement, atom != nullptr); @@ -1462,10 +1452,6 @@ Parser::newFunction(HandleAtom atom, FunctionSyntaxKind kind, : JSFunction::INTERPRETED_GENERATOR); } - // We store the async wrapper in a slot for later access. - if (asyncKind == AsyncFunction) - allocKind = gc::AllocKind::FUNCTION_EXTENDED; - fun = NewFunctionWithProto(context, nullptr, 0, flags, nullptr, atom, proto, allocKind, TenuredObject); if (!fun) @@ -1847,7 +1833,7 @@ Parser::bindDestructuringArg(BindData* data, template bool Parser::functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind, - FunctionAsyncKind asyncKind, Node funcpn, bool* hasRest) + Node funcpn, bool* hasRest) { FunctionBox* funbox = pc->sc->asFunctionBox(); @@ -2035,20 +2021,11 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn // before the first default argument. funbox->length = pc->numArgs() - 1; } - bool awaitIsKeyword; - if (asyncKind == AsyncFunction) { - awaitIsKeyword = tokenStream.getAwaitIsKeyword(); - tokenStream.setAwaitIsKeyword(true); - } - Node def_expr = assignExprWithoutYieldAndAwait(yieldHandling, JSMSG_YIELD_IN_DEFAULT); - + Node def_expr = assignExprWithoutYield(yieldHandling, JSMSG_YIELD_IN_DEFAULT); if (!def_expr) return false; if (!handler.setLastFunctionArgumentDefault(funcpn, def_expr)) return false; - if (asyncKind == AsyncFunction) { - tokenStream.setAwaitIsKeyword(awaitIsKeyword); - } } if (parenFreeArrow || IsSetterKind(kind)) @@ -2233,7 +2210,7 @@ Parser::checkFunctionDefinition(HandlePropertyName funName, RootedFunction fun(context, handler.nextLazyInnerFunction()); MOZ_ASSERT(!fun->isLegacyGenerator()); FunctionBox* funbox = newFunctionBox(pn, fun, pc, Directives(/* strict = */ false), - fun->generatorKind(), fun->asyncKind()); + fun->generatorKind()); if (!funbox) return false; @@ -2442,11 +2419,9 @@ template typename ParseHandler::Node Parser::functionDef(InHandling inHandling, YieldHandling yieldHandling, HandlePropertyName funName, FunctionSyntaxKind kind, - GeneratorKind generatorKind, FunctionAsyncKind asyncKind, - InvokedPrediction invoked) + GeneratorKind generatorKind, InvokedPrediction invoked) { MOZ_ASSERT_IF(kind == Statement, funName); - MOZ_ASSERT_IF(asyncKind == AsyncFunction, generatorKind == StarGenerator); /* Make a TOK_FUNCTION node. */ Node pn = handler.newFunctionDefinition(); @@ -2473,7 +2448,7 @@ Parser::functionDef(InHandling inHandling, YieldHandling yieldHand if (!proto) return null(); } - RootedFunction fun(context, newFunction(funName, kind, generatorKind, asyncKind, proto)); + RootedFunction fun(context, newFunction(funName, kind, generatorKind, proto)); if (!fun) return null(); @@ -2488,8 +2463,8 @@ Parser::functionDef(InHandling inHandling, YieldHandling yieldHand tokenStream.tell(&start); while (true) { - if (functionArgsAndBody(inHandling, pn, fun, kind, generatorKind, asyncKind, - directives, &newDirectives)) + if (functionArgsAndBody(inHandling, pn, fun, kind, generatorKind, directives, + &newDirectives)) { break; } @@ -2559,7 +2534,6 @@ Parser::finishFunctionDefinition(Node pn, FunctionBox* funbo if (pc->sc->strict()) lazy->setStrict(); lazy->setGeneratorKind(funbox->generatorKind()); - lazy->setAsyncKind(funbox->asyncKind()); if (funbox->usesArguments && funbox->usesApply && funbox->usesThis) lazy->setUsesArgumentsApplyAndThis(); if (funbox->isDerivedClassConstructor()) @@ -2577,14 +2551,13 @@ bool Parser::functionArgsAndBody(InHandling inHandling, ParseNode* pn, HandleFunction fun, FunctionSyntaxKind kind, GeneratorKind generatorKind, - FunctionAsyncKind asyncKind, Directives inheritedDirectives, Directives* newDirectives) { ParseContext* outerpc = pc; // Create box for fun->object early to protect against last-ditch GC. - FunctionBox* funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind, asyncKind); + FunctionBox* funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind); if (!funbox) return false; @@ -2683,14 +2656,13 @@ bool Parser::functionArgsAndBody(InHandling inHandling, Node pn, HandleFunction fun, FunctionSyntaxKind kind, GeneratorKind generatorKind, - FunctionAsyncKind asyncKind, Directives inheritedDirectives, Directives* newDirectives) { ParseContext* outerpc = pc; // Create box for fun->object early to protect against last-ditch GC. - FunctionBox* funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind, asyncKind); + FunctionBox* funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind); if (!funbox) return false; @@ -2706,6 +2678,7 @@ Parser::functionArgsAndBody(InHandling inHandling, Node pn, if (!leaveFunction(pn, outerpc, kind)) return false; + // This is a lazy function inner to another lazy function. Remember the // inner function so that if the outer function is eventually parsed we do // not need any further parsing or processing of the inner function. @@ -2734,8 +2707,7 @@ Parser::appendToCallSiteObj(Node callSiteObj) template <> ParseNode* Parser::standaloneLazyFunction(HandleFunction fun, bool strict, - GeneratorKind generatorKind, - FunctionAsyncKind asyncKind) + GeneratorKind generatorKind) { MOZ_ASSERT(checkOptionsCalled); @@ -2750,7 +2722,7 @@ Parser::standaloneLazyFunction(HandleFunction fun, bool strict RootedObject enclosing(context, fun->lazyScript()->enclosingScope()); Directives directives(/* strict = */ strict); - FunctionBox* funbox = newFunctionBox(pn, fun, directives, generatorKind, asyncKind, enclosing); + FunctionBox* funbox = newFunctionBox(pn, fun, directives, generatorKind, enclosing); if (!funbox) return null(); funbox->length = fun->nargs() - fun->hasRest(); @@ -2808,12 +2780,12 @@ Parser::functionArgsAndBodyGeneric(InHandling inHandling, // function without concern for conversion to strict mode, use of lazy // parsing and such. - FunctionBox* funbox = pc->sc->asFunctionBox(); - bool hasRest; - if (!functionArguments(yieldHandling, kind, funbox->asyncKind(), pn, &hasRest)) + if (!functionArguments(yieldHandling, kind, pn, &hasRest)) return false; + FunctionBox* funbox = pc->sc->asFunctionBox(); + fun->setArgCount(pc->numArgs()); if (hasRest) fun->setHasRest(); @@ -2857,12 +2829,9 @@ Parser::functionArgsAndBodyGeneric(InHandling inHandling, #endif } - bool beforeAwaitIsKeyword = tokenStream.getAwaitIsKeyword(); - tokenStream.setAwaitIsKeyword(funbox->isAsync()); Node body = functionBody(inHandling, yieldHandling, kind, bodyType); if (!body) return false; - tokenStream.setAwaitIsKeyword(beforeAwaitIsKeyword); if ((kind != Method && !IsConstructorKind(kind)) && fun->name() && !checkStrictBinding(fun->name(), pn)) @@ -2908,8 +2877,7 @@ Parser::checkYieldNameValidity() template typename ParseHandler::Node -Parser::functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling, - FunctionAsyncKind asyncKind) +Parser::functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling) { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION)); @@ -2920,10 +2888,6 @@ Parser::functionStmt(YieldHandling yieldHandling, DefaultHandling return null(); if (tt == TOK_MUL) { - if (asyncKind != SyncFunction) { - report(ParseError, false, null(), JSMSG_ASYNC_GENERATOR); - return null(); - } generatorKind = StarGenerator; if (!tokenStream.getToken(&tt)) return null(); @@ -2949,14 +2913,12 @@ Parser::functionStmt(YieldHandling yieldHandling, DefaultHandling !report(ParseStrictError, pc->sc->strict(), null(), JSMSG_STRICT_FUNCTION_STATEMENT)) return null(); - if (asyncKind == AsyncFunction) - generatorKind = StarGenerator; - return functionDef(InAllowed, yieldHandling, name, Statement, generatorKind, asyncKind); + return functionDef(InAllowed, yieldHandling, name, Statement, generatorKind); } template typename ParseHandler::Node -Parser::functionExpr(InvokedPrediction invoked, FunctionAsyncKind asyncKind) +Parser::functionExpr(InvokedPrediction invoked) { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION)); @@ -2966,10 +2928,6 @@ Parser::functionExpr(InvokedPrediction invoked, FunctionAsyncKind return null(); if (tt == TOK_MUL) { - if (asyncKind != SyncFunction) { - report(ParseError, false, null(), JSMSG_ASYNC_GENERATOR); - return null(); - } generatorKind = StarGenerator; if (!tokenStream.getToken(&tt)) return null(); @@ -2986,10 +2944,8 @@ Parser::functionExpr(InvokedPrediction invoked, FunctionAsyncKind tokenStream.ungetToken(); } - if (asyncKind == AsyncFunction) - generatorKind = StarGenerator; YieldHandling yieldHandling = generatorKind != NotGenerator ? YieldIsKeyword : YieldIsName; - return functionDef(InAllowed, yieldHandling, name, Expression, generatorKind, asyncKind, invoked); + return functionDef(InAllowed, yieldHandling, name, Expression, generatorKind, invoked); } /* @@ -4977,7 +4933,7 @@ Parser::exportDeclaration() } case TOK_FUNCTION: - kid = functionStmt(YieldIsKeyword, NameRequired, SyncFunction); + kid = functionStmt(YieldIsKeyword, NameRequired); if (!kid) return null(); @@ -5027,7 +4983,7 @@ Parser::exportDeclaration() ParseNode* binding = nullptr; switch (tt) { case TOK_FUNCTION: - kid = functionStmt(YieldIsKeyword, AllowDefaultName, SyncFunction); + kid = functionStmt(YieldIsKeyword, AllowDefaultName); if (!kid) return null(); break; @@ -6012,7 +5968,7 @@ Parser::returnStatement(YieldHandling yieldHandling) template typename ParseHandler::Node Parser::newYieldExpression(uint32_t begin, typename ParseHandler::Node expr, - bool isYieldStar, bool isAwait) + bool isYieldStar) { Node generator = newName(context->names().dotGenerator); if (!generator) @@ -6021,9 +5977,7 @@ Parser::newYieldExpression(uint32_t begin, typename ParseHandler:: return null(); if (isYieldStar) return handler.newYieldStarExpression(begin, expr, generator); - if (isAwait) - return handler.newAwaitExpression(begin, expr, generator); - return handler.newYieldExpression(begin, expr, generator, JSOP_YIELD); + return handler.newYieldExpression(begin, expr, generator); } template @@ -6476,7 +6430,6 @@ JSOpFromPropertyType(PropertyType propType) case PropertyType::Normal: case PropertyType::Method: case PropertyType::GeneratorMethod: - case PropertyType::AsyncMethod: case PropertyType::Constructor: case PropertyType::DerivedConstructor: return JSOP_INITPROP; @@ -6498,8 +6451,8 @@ FunctionSyntaxKindFromPropertyType(PropertyType propType) case PropertyType::SetterNoExpressionClosure: return SetterNoExpressionClosure; case PropertyType::Method: + return Method; case PropertyType::GeneratorMethod: - case PropertyType::AsyncMethod: return Method; case PropertyType::Constructor: return ClassConstructor; @@ -6513,15 +6466,7 @@ FunctionSyntaxKindFromPropertyType(PropertyType propType) static GeneratorKind GeneratorKindFromPropertyType(PropertyType propType) { - return (propType == PropertyType::GeneratorMethod || - propType == PropertyType::AsyncMethod) - ? StarGenerator : NotGenerator; -} - -static FunctionAsyncKind -AsyncKindFromPropertyType(PropertyType propType) -{ - return propType == PropertyType::AsyncMethod ? AsyncFunction : SyncFunction; + return propType == PropertyType::GeneratorMethod ? StarGenerator : NotGenerator; } template <> @@ -6635,7 +6580,6 @@ Parser::classDefinition(YieldHandling yieldHandling, if (propType != PropertyType::Getter && propType != PropertyType::Setter && propType != PropertyType::Method && propType != PropertyType::GeneratorMethod && - propType != PropertyType::AsyncMethod && propType != PropertyType::Constructor && propType != PropertyType::DerivedConstructor) { report(ParseError, false, null(), JSMSG_BAD_METHOD_DEF); @@ -6804,19 +6748,6 @@ Parser::statement(YieldHandling yieldHandling, bool canHaveDirecti case TOK_NAME: { TokenKind next; - -#ifdef JS_HAS_ASYNC_FUNCS - if (tokenStream.currentName() == context->names().async) { - TokenKind nextSameLine = TOK_EOF; - if (!tokenStream.peekTokenSameLine(&nextSameLine)) - return null(); - if (nextSameLine == TOK_FUNCTION) { - tokenStream.consumeKnownToken(TOK_FUNCTION); - return functionStmt(yieldHandling, NameRequired, AsyncFunction); - } - } -#endif - if (!tokenStream.peekToken(&next)) return null(); if (next == TOK_COLON) @@ -6891,7 +6822,7 @@ Parser::statement(YieldHandling yieldHandling, bool canHaveDirecti // HoistableDeclaration[?Yield] case TOK_FUNCTION: - return functionStmt(yieldHandling, NameRequired, SyncFunction); + return functionStmt(yieldHandling, NameRequired); // ClassDeclaration[?Yield] case TOK_CLASS: @@ -7205,19 +7136,6 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl bool endsExpr; if (tt == TOK_NAME) { -#ifdef JS_HAS_ASYNC_FUNCS - if (tokenStream.currentName() == context->names().async) { - TokenKind nextSameLine = TOK_EOF; - if (!tokenStream.peekTokenSameLine(&nextSameLine)) - return null(); - - if (nextSameLine == TOK_FUNCTION) { - tokenStream.consumeKnownToken(TOK_FUNCTION); - return functionExpr(PredictUninvoked, AsyncFunction); - } - } -#endif - if (!tokenStream.nextTokenEndsExpr(&endsExpr)) return null(); if (endsExpr) @@ -7238,14 +7156,8 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl return stringLiteral(); } - if (tt == TOK_YIELD && yieldExpressionsSupported()) { - if (pc->isAsync()) { - report(ParseError, false, null(), JSMSG_YIELD_IN_ASYNC); - return null(); - } + if (tt == TOK_YIELD && yieldExpressionsSupported()) return yieldExpression(inHandling); - } - tokenStream.ungetToken(); @@ -7305,7 +7217,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl return null(); } - Node arrowFunc = functionDef(inHandling, yieldHandling, nullptr, Arrow, NotGenerator, SyncFunction); + Node arrowFunc = functionDef(inHandling, yieldHandling, nullptr, Arrow, NotGenerator); if (!arrowFunc) return null(); @@ -7567,27 +7479,6 @@ Parser::unaryExpr(YieldHandling yieldHandling, InvokedPrediction i return handler.newDelete(begin, expr); } - case TOK_AWAIT: - { -#ifndef JS_HAS_ASYNC_FUNCS - MOZ_CRASH("Should not see TOK_AWAIT without async function support"); -#endif - - TokenKind nextSameLine = TOK_EOF; - - if (!tokenStream.peekTokenSameLine(&nextSameLine, TokenStream::Operand)) - return null(); - if (nextSameLine != TOK_EOL) { - Node kid = unaryExpr(yieldHandling); - if (!kid) - return null(); - return newYieldExpression(begin, kid, /* isYieldStar = */ false, /* isAwait = */ true); - } else { - report(ParseError, false, null(), JSMSG_LINE_BREAK_AFTER_AWAIT); - return null(); - } - } - default: { Node pn = memberExpr(yieldHandling, tt, /* allowCallSyntax = */ true, invoked); if (!pn) @@ -8165,13 +8056,13 @@ Parser::generatorComprehensionLambda(GeneratorKind comprehensionKi } RootedFunction fun(context, newFunction(/* atom = */ nullptr, Expression, - comprehensionKind, SyncFunction, proto)); + comprehensionKind, proto)); if (!fun) return null(); // Create box for fun->object early to root it. Directives directives(/* strict = */ outerpc->sc->strict()); - FunctionBox* genFunbox = newFunctionBox(genfn, fun, outerpc, directives, comprehensionKind, SyncFunction); + FunctionBox* genFunbox = newFunctionBox(genfn, fun, outerpc, directives, comprehensionKind); if (!genFunbox) return null(); @@ -8499,16 +8390,8 @@ Parser::generatorComprehension(uint32_t begin) template typename ParseHandler::Node -Parser::assignExprWithoutYieldAndAwait(YieldHandling yieldHandling, unsigned msg) +Parser::assignExprWithoutYield(YieldHandling yieldHandling, unsigned msg) { - TokenKind tt; - if (!tokenStream.peekToken(&tt, TokenStream::Operand)) - return null(); - - if (tt == TOK_AWAIT) { - report(ParseError, false, null(), JSMSG_AWAIT_IN_DEFAULT); - return null(); - } uint32_t startYieldOffset = pc->lastYieldOffset; Node res = assignExpr(InAllowed, yieldHandling); if (res && pc->lastYieldOffset != startYieldOffset) { @@ -9040,32 +8923,12 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, MOZ_ASSERT(ltok != TOK_RC); bool isGenerator = false; - bool isAsync = false; - if (ltok == TOK_MUL) { isGenerator = true; if (!tokenStream.getToken(<ok, TokenStream::KeywordIsName)) return null(); } - if (ltok == TOK_NAME && tokenStream.currentName() == context->names().async) { - TokenKind tt; - if (!tokenStream.getToken(&tt, TokenStream::KeywordIsName)) - return null(); - if (tt != TOK_LP && tt != TOK_COLON) { - isAsync = true; - ltok = tt; - } else { - tokenStream.ungetToken(); - tokenStream.addModifierException(TokenStream::NoneIsKeywordIsName); - } - } - - if (isAsync && isGenerator) { - report(ParseError, false, null(), JSMSG_ASYNC_GENERATOR); - return null(); - } - propAtom.set(nullptr); Node propName; switch (ltok) { @@ -9087,7 +8950,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, case TOK_NAME: { propAtom.set(tokenStream.currentName()); // Do not look for accessor syntax on generators - if (isGenerator || isAsync || + if (isGenerator || !(propAtom.get() == context->names().get || propAtom.get() == context->names().set)) { @@ -9204,8 +9067,7 @@ Parser::propertyName(YieldHandling yieldHandling, Node propList, if (tt == TOK_LP) { tokenStream.ungetToken(); - *propType = isGenerator ? PropertyType::GeneratorMethod : - (isAsync ? PropertyType::AsyncMethod : PropertyType::Method); + *propType = isGenerator ? PropertyType::GeneratorMethod : PropertyType::Method; return propName; } @@ -9352,8 +9214,7 @@ Parser::methodDefinition(YieldHandling yieldHandling, PropertyType { FunctionSyntaxKind kind = FunctionSyntaxKindFromPropertyType(propType); GeneratorKind generatorKind = GeneratorKindFromPropertyType(propType); - FunctionAsyncKind asyncKind = AsyncKindFromPropertyType(propType); - return functionDef(InAllowed, yieldHandling, funName, kind, generatorKind, asyncKind); + return functionDef(InAllowed, yieldHandling, funName, kind, generatorKind); } template @@ -9462,8 +9323,7 @@ Parser::primaryExpr(YieldHandling yieldHandling, TokenKind tt, case TOK_YIELD: if (!checkYieldNameValidity()) return null(); - - // Fall through. + // Fall through. case TOK_NAME: return identifierName(yieldHandling); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 6f49a0536dab..b929ec50447e 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -127,8 +127,6 @@ struct MOZ_STACK_CLASS ParseContext : public GenericParseContext bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; } bool isStarGenerator() const { return generatorKind() == StarGenerator; } - bool isAsync() const { return sc->isFunctionBox() && sc->asFunctionBox()->isAsync(); } - bool isArrowFunction() const { return sc->isFunctionBox() && sc->asFunctionBox()->function()->isArrow(); } @@ -365,7 +363,6 @@ enum class PropertyType { SetterNoExpressionClosure, Method, GeneratorMethod, - AsyncMethod, Constructor, DerivedConstructor }; @@ -507,26 +504,22 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter ObjectBox* newObjectBox(JSObject* obj); FunctionBox* newFunctionBox(Node fn, JSFunction* fun, ParseContext* outerpc, Directives directives, GeneratorKind generatorKind, - FunctionAsyncKind asyncKind, JSObject* enclosingStaticScope); // Use when the funbox is the outermost. FunctionBox* newFunctionBox(Node fn, HandleFunction fun, Directives directives, - GeneratorKind generatorKind, - FunctionAsyncKind asyncKind, - HandleObject enclosingStaticScope) + GeneratorKind generatorKind, HandleObject enclosingStaticScope) { return newFunctionBox(fn, fun, nullptr, directives, generatorKind, - asyncKind, enclosingStaticScope); + enclosingStaticScope); } // Use when the funbox should be linked to the outerpc's innermost scope. FunctionBox* newFunctionBox(Node fn, HandleFunction fun, ParseContext* outerpc, - Directives directives, GeneratorKind generatorKind, - FunctionAsyncKind asyncKind) + Directives directives, GeneratorKind generatorKind) { RootedObject enclosing(context, outerpc->innermostStaticScope()); - return newFunctionBox(fn, fun, outerpc, directives, generatorKind, asyncKind, enclosing); + return newFunctionBox(fn, fun, outerpc, directives, generatorKind, enclosing); } ModuleBox* newModuleBox(Node pn, HandleModuleObject module); @@ -536,7 +529,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter * a function expression). */ JSFunction* newFunction(HandleAtom atom, FunctionSyntaxKind kind, GeneratorKind generatorKind, - FunctionAsyncKind asyncKind, HandleObject proto); + HandleObject proto); bool generateBlockId(JSObject* staticScope, uint32_t* blockIdOut) { if (blockScopes.length() == StmtInfoPC::BlockIdLimit) { @@ -575,7 +568,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter TokenKind* ttp); inline Node newName(PropertyName* name); - inline Node newYieldExpression(uint32_t begin, Node expr, bool isYieldStar = false, bool isAsync = false); + inline Node newYieldExpression(uint32_t begin, Node expr, bool isYieldStar = false); inline bool abortIfSyntaxParser(); @@ -596,14 +589,13 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter // Parse a function, given only its body. Used for the Function and // Generator constructors. Node standaloneFunctionBody(HandleFunction fun, Handle formals, - GeneratorKind generatorKind, FunctionAsyncKind asyncKind, + GeneratorKind generatorKind, Directives inheritedDirectives, Directives* newDirectives, HandleObject enclosingStaticScope); // Parse a function, given only its arguments and body. Used for lazily // parsed functions. - Node standaloneLazyFunction(HandleFunction fun, bool strict, GeneratorKind generatorKind, - FunctionAsyncKind asyncKind); + Node standaloneLazyFunction(HandleFunction fun, bool strict, GeneratorKind generatorKind); /* * Parse a function body. Pass StatementListBody if the body is a list of @@ -655,10 +647,8 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter * Some parsers have two versions: an always-inlined version (with an 'i' * suffix) and a never-inlined version (with an 'n' suffix). */ - Node functionStmt(YieldHandling yieldHandling, - DefaultHandling defaultHandling, FunctionAsyncKind asyncKind); - Node functionExpr(InvokedPrediction invoked = PredictUninvoked, - FunctionAsyncKind asyncKind = SyncFunction); + Node functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling); + Node functionExpr(InvokedPrediction invoked = PredictUninvoked); Node statements(YieldHandling yieldHandling); Node blockStatement(YieldHandling yieldHandling); @@ -691,7 +681,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter InvokedPrediction invoked = PredictUninvoked); Node assignExpr(InHandling inHandling, YieldHandling yieldHandling, InvokedPrediction invoked = PredictUninvoked); - Node assignExprWithoutYieldAndAwait(YieldHandling yieldHandling, unsigned err); + Node assignExprWithoutYield(YieldHandling yieldHandling, unsigned err); Node yieldExpression(InHandling inHandling); Node condExpr1(InHandling inHandling, YieldHandling yieldHandling, InvokedPrediction invoked = PredictUninvoked); @@ -715,13 +705,13 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter * Additional JS parsers. */ bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind, - FunctionAsyncKind asyncKind, Node funcpn, bool* hasRest); + Node funcpn, bool* hasRest); Node functionDef(InHandling inHandling, YieldHandling uieldHandling, HandlePropertyName name, - FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, + FunctionSyntaxKind kind, GeneratorKind generatorKind, InvokedPrediction invoked = PredictUninvoked); bool functionArgsAndBody(InHandling inHandling, Node pn, HandleFunction fun, - FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, + FunctionSyntaxKind kind, GeneratorKind generatorKind, Directives inheritedDirectives, Directives* newDirectives); Node unaryOpExpr(YieldHandling yieldHandling, ParseNodeKind kind, JSOp op, uint32_t begin); @@ -832,7 +822,6 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter // Top-level entrypoint into destructuring pattern checking/name-analyzing. bool checkDestructuringPattern(BindData* data, Node pattern); - // Recursive methods for checking/name-analyzing subcomponents of a // destructuring pattern. The array/object methods *must* be passed arrays // or objects. The name method may be passed anything but will report an diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h index 82030ec10fb8..7ccabafccfb2 100644 --- a/js/src/frontend/SharedContext.h +++ b/js/src/frontend/SharedContext.h @@ -301,13 +301,10 @@ class FunctionBox : public ObjectBox, public SharedContext FunctionContextFlags funCxFlags; - FunctionAsyncKind _asyncKind; - template FunctionBox(ExclusiveContext* cx, ObjectBox* traceListHead, JSFunction* fun, JSObject* enclosingStaticScope, ParseContext* pc, - Directives directives, bool extraWarnings, GeneratorKind generatorKind, - FunctionAsyncKind asyncKind); + Directives directives, bool extraWarnings, GeneratorKind generatorKind); ObjectBox* toObjectBox() override { return this; } JSFunction* function() const { return &object->as(); } @@ -319,8 +316,6 @@ class FunctionBox : public ObjectBox, public SharedContext bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; } bool isStarGenerator() const { return generatorKind() == StarGenerator; } bool isArrow() const { return function()->isArrow(); } - bool isAsync() const { return _asyncKind == AsyncFunction; } - FunctionAsyncKind asyncKind() const { return _asyncKind; } void setGeneratorKind(GeneratorKind kind) { // A generator kind can be set at initialization, or when "yield" is diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index a7ff12a0f8e0..da8b1841c5ed 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -283,9 +283,8 @@ class SyntaxParseHandler bool addShorthand(Node literal, Node name, Node expr) { return true; } bool addObjectMethodDefinition(Node literal, Node name, Node fn, JSOp op) { return true; } bool addClassMethodDefinition(Node literal, Node name, Node fn, JSOp op, bool isStatic) { return true; } - Node newYieldExpression(uint32_t begin, Node value, Node gen, JSOp op) { return NodeUnparenthesizedYieldExpr; } + Node newYieldExpression(uint32_t begin, Node value, Node gen) { return NodeUnparenthesizedYieldExpr; } Node newYieldStarExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; } - Node newAwaitExpression(uint32_t begin, Node value, Node gen) { return NodeUnparenthesizedYieldExpr; } // Statements diff --git a/js/src/frontend/TokenKind.h b/js/src/frontend/TokenKind.h index 1a5d3af3c486..83ee7717257c 100644 --- a/js/src/frontend/TokenKind.h +++ b/js/src/frontend/TokenKind.h @@ -107,8 +107,6 @@ macro(THROW, "keyword 'throw'") \ macro(DEBUGGER, "keyword 'debugger'") \ macro(YIELD, "keyword 'yield'") \ - macro(ASYNC, "keyword 'async'") \ - macro(AWAIT, "keyword 'await'") \ macro(LET, "keyword 'let'") \ macro(EXPORT, "keyword 'export'") \ macro(IMPORT, "keyword 'import'") \ diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index 297787d7a0c0..8b24da477305 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -986,11 +986,6 @@ TokenStream::putIdentInTokenbuf(const char16_t* identStart) bool TokenStream::checkForKeyword(const KeywordInfo* kw, TokenKind* ttp) { - if (!awaitIsKeyword && kw->tokentype == TOK_AWAIT) { - *ttp = TOK_NAME; - return true; - } - if (kw->tokentype == TOK_RESERVED #ifndef JS_HAS_CLASSES || kw->tokentype == TOK_CLASS diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index ff969625ea85..e3601b0ba68b 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -445,8 +445,6 @@ class MOZ_STACK_CLASS TokenStream {} }; - bool awaitIsKeyword = false; - public: typedef Token::Modifier Modifier; static MOZ_CONSTEXPR_VAR Modifier None = Token::None; @@ -687,14 +685,6 @@ class MOZ_STACK_CLASS TokenStream return true; } - bool getAwaitIsKeyword() { - return awaitIsKeyword; - } - - void setAwaitIsKeyword(bool _awaitIsKeyword) { - awaitIsKeyword = _awaitIsKeyword; - } - class MOZ_STACK_CLASS Position { public: // The Token fields may contain pointers to atoms, so for correct diff --git a/js/src/jit-test/lib/class.js b/js/src/jit-test/lib/class.js index 0f5860c5d107..eea50788a4d2 100644 --- a/js/src/jit-test/lib/class.js +++ b/js/src/jit-test/lib/class.js @@ -1,2 +1 @@ -// classesEnabled ended up needing a fairly broad scope. -load(libdir + "../../tests/shell.js"); +load(libdir + "../../tests/ecma_6/shell.js"); diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index 1fb654143a52..8bd153bf2b17 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -2496,15 +2496,15 @@ static const VMFunction DefFunOperationInfo = FunctionInfo(De bool BaselineCompiler::emit_JSOP_DEFFUN() { + RootedFunction fun(cx, script->getFunction(GET_UINT32_INDEX(pc))); - frame.popRegsAndSync(1); - masm.unboxObject(R0, R0.scratchReg()); - masm.loadPtr(frame.addressOfScopeChain(), R1.scratchReg()); + frame.syncStack(0); + masm.loadPtr(frame.addressOfScopeChain(), R0.scratchReg()); prepareVMCall(); + pushArg(ImmGCPtr(fun)); pushArg(R0.scratchReg()); - pushArg(R1.scratchReg()); pushArg(ImmGCPtr(script)); return callVM(DefFunOperationInfo); diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 034ebb77a50f..befb0a9703a5 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -3737,9 +3737,8 @@ void CodeGenerator::visitDefFun(LDefFun* lir) { Register scopeChain = ToRegister(lir->scopeChain()); - Register fun = ToRegister(lir->fun()); - pushArg(fun); + pushArg(ImmGCPtr(lir->mir()->fun())); pushArg(scopeChain); pushArg(ImmGCPtr(current->mir()->info().script())); diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 05220414063f..9dd58efe9e1a 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -12585,11 +12585,13 @@ IonBuilder::jsop_defvar(uint32_t index) bool IonBuilder::jsop_deffun(uint32_t index) { + JSFunction* fun = script()->getFunction(index); + if (fun->isNative() && IsAsmJSModuleNative(fun->native())) + return abort("asm.js module function"); + MOZ_ASSERT(analysis().usesScopeChain()); - MDefinition *funDef = current->pop(); - - MDefFun* deffun = MDefFun::New(alloc(), funDef, current->scopeChain()); + MDefFun* deffun = MDefFun::New(alloc(), fun, current->scopeChain()); current->add(deffun); return resumeAfter(deffun); diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 95ffc97efc04..bae8688a4434 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -156,11 +156,7 @@ LIRGenerator::visitDefVar(MDefVar* ins) void LIRGenerator::visitDefFun(MDefFun* ins) { - MDefinition* fun = ins->fun(); - MOZ_ASSERT(fun->type() == MIRType_Object); - - LDefFun* lir = new(alloc()) LDefFun(useRegisterAtStart(fun), - useRegisterAtStart(ins->scopeChain())); + LDefFun* lir = new(alloc()) LDefFun(useRegisterAtStart(ins->scopeChain())); add(lir, ins); assignSafepoint(lir, ins); } diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 2f7779ff14a1..40779372ce96 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -7319,26 +7319,29 @@ class MDefVar }; class MDefFun - : public MBinaryInstruction, - public ObjectPolicy<0>::Data + : public MUnaryInstruction, + public NoTypePolicy::Data { + CompilerFunction fun_; + private: - MDefFun(MDefinition* fun, MDefinition* scopeChain) - : MBinaryInstruction(fun, scopeChain) + MDefFun(JSFunction* fun, MDefinition* scopeChain) + : MUnaryInstruction(scopeChain), + fun_(fun) {} public: INSTRUCTION_HEADER(DefFun) - static MDefFun* New(TempAllocator& alloc, MDefinition* fun, MDefinition* scopeChain) { + static MDefFun* New(TempAllocator& alloc, JSFunction* fun, MDefinition* scopeChain) { return new(alloc) MDefFun(fun, scopeChain); } - MDefinition* fun() const { - return getOperand(0); + JSFunction* fun() const { + return fun_; } MDefinition* scopeChain() const { - return getOperand(1); + return getOperand(0); } bool possiblyCalls() const override { return true; diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h index f4a77ef30340..56f5416d97eb 100644 --- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -1228,22 +1228,18 @@ class LDefVar : public LCallInstructionHelper<0, 1, 0> } }; -class LDefFun : public LCallInstructionHelper<0, 2, 0> +class LDefFun : public LCallInstructionHelper<0, 1, 0> { public: LIR_HEADER(DefFun) - LDefFun(const LAllocation& fun, const LAllocation& scopeChain) + explicit LDefFun(const LAllocation& scopeChain) { - setOperand(0, fun); - setOperand(1, scopeChain); + setOperand(0, scopeChain); } - const LAllocation* fun() { - return getOperand(0); - } const LAllocation* scopeChain() { - return getOperand(1); + return getOperand(0); } MDefFun* mir() const { return mir_->toDefFun(); diff --git a/js/src/js.msg b/js/src/js.msg index 72d6faa3bca8..b7f41bd6a8fd 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -106,8 +106,6 @@ MSG_DEF(JSMSG_TERMINATED, 1, JSEXN_ERR, "Script terminated by timeo MSG_DEF(JSMSG_PROTO_NOT_OBJORNULL, 1, JSEXN_TYPEERR, "{0}.prototype is not an object or null") MSG_DEF(JSMSG_CANT_CALL_CLASS_CONSTRUCTOR, 0, JSEXN_TYPEERR, "class constructors must be invoked with |new|") MSG_DEF(JSMSG_DISABLED_DERIVED_CLASS, 1, JSEXN_INTERNALERR, "{0} temporarily disallowed in derived class constructors") -MSG_DEF(JSMSG_NOT_CALLABLE, 1, JSEXN_TYPEERR, "{0} is not callable") -MSG_DEF(JSMSG_NOT_IMPLEMENTED, 1, JSEXN_INTERNALERR, "{0} is not implemented") // JSON MSG_DEF(JSMSG_JSON_BAD_PARSE, 3, JSEXN_SYNTAXERR, "JSON.parse: {0} at line {1} column {2} of the JSON data") @@ -188,9 +186,6 @@ MSG_DEF(JSMSG_ARRAY_COMP_LEFTSIDE, 0, JSEXN_SYNTAXERR, "invalid array compre MSG_DEF(JSMSG_ARRAY_INIT_TOO_BIG, 0, JSEXN_INTERNALERR, "array initialiser too large") MSG_DEF(JSMSG_AS_AFTER_IMPORT_STAR, 0, JSEXN_SYNTAXERR, "missing keyword 'as' after import *") MSG_DEF(JSMSG_AS_AFTER_RESERVED_WORD, 1, JSEXN_SYNTAXERR, "missing keyword 'as' after reserved word '{0}'") -MSG_DEF(JSMSG_ASYNC_ACCESSOR, 0, JSEXN_SYNTAXERR, "async getters and setters are not allowed") -MSG_DEF(JSMSG_ASYNC_CONSTRUCTOR, 0, JSEXN_SYNTAXERR, "constructor may not be async") -MSG_DEF(JSMSG_ASYNC_GENERATOR, 0, JSEXN_SYNTAXERR, "generator function or method may not be async") MSG_DEF(JSMSG_BAD_ANON_GENERATOR_RETURN, 0, JSEXN_TYPEERR, "anonymous generator function returns a value") MSG_DEF(JSMSG_BAD_ARROW_ARGS, 0, JSEXN_SYNTAXERR, "invalid arrow-function arguments (parentheses around the arrow-function may help)") MSG_DEF(JSMSG_BAD_BINDING, 1, JSEXN_SYNTAXERR, "redefining {0} is deprecated") @@ -272,7 +267,6 @@ MSG_DEF(JSMSG_LABEL_NOT_FOUND, 0, JSEXN_SYNTAXERR, "label not found") MSG_DEF(JSMSG_LET_CLASS_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a class") MSG_DEF(JSMSG_LET_COMP_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a comprehension variable") MSG_DEF(JSMSG_LEXICAL_DECL_NOT_IN_BLOCK, 1, JSEXN_SYNTAXERR, "{0} declaration not directly within block") -MSG_DEF(JSMSG_LINE_BREAK_AFTER_AWAIT, 0, JSEXN_SYNTAXERR, "no line break is allowed after 'await'") MSG_DEF(JSMSG_LINE_BREAK_AFTER_THROW, 0, JSEXN_SYNTAXERR, "no line break is allowed between 'throw' and its expression") MSG_DEF(JSMSG_MALFORMED_ESCAPE, 1, JSEXN_SYNTAXERR, "malformed {0} character escape sequence") MSG_DEF(JSMSG_MISSING_BINARY_DIGITS, 0, JSEXN_SYNTAXERR, "missing binary digits after '0b'") @@ -345,9 +339,7 @@ MSG_DEF(JSMSG_USE_ASM_DIRECTIVE_FAIL, 0, JSEXN_SYNTAXERR, "\"use asm\" is only MSG_DEF(JSMSG_VAR_HIDES_ARG, 1, JSEXN_TYPEERR, "variable {0} redeclares argument") MSG_DEF(JSMSG_WHILE_AFTER_DO, 0, JSEXN_SYNTAXERR, "missing while after do-loop body") MSG_DEF(JSMSG_YIELD_IN_ARROW, 0, JSEXN_SYNTAXERR, "arrow function may not contain yield") -MSG_DEF(JSMSG_YIELD_IN_ASYNC, 0, JSEXN_SYNTAXERR, "async function may not contain yield") MSG_DEF(JSMSG_YIELD_IN_DEFAULT, 0, JSEXN_SYNTAXERR, "yield in default expression") -MSG_DEF(JSMSG_AWAIT_IN_DEFAULT, 0, JSEXN_SYNTAXERR, "await in default expression") MSG_DEF(JSMSG_BAD_COLUMN_NUMBER, 0, JSEXN_RANGEERR, "column number out of range") MSG_DEF(JSMSG_COMPUTED_NAME_IN_PATTERN,0, JSEXN_SYNTAXERR, "computed property names aren't supported in this destructuring declaration") MSG_DEF(JSMSG_DEFAULT_IN_PATTERN, 0, JSEXN_SYNTAXERR, "destructuring defaults aren't supported in this destructuring declaration") @@ -516,10 +508,6 @@ MSG_DEF(JSMSG_NO_INDEXED_SETTER, 2, JSEXN_TYPEERR, "{0} doesn't have an // Super MSG_DEF(JSMSG_CANT_DELETE_SUPER, 0, JSEXN_REFERENCEERR, "invalid delete involving 'super'") -// Promise -MSG_DEF(JSMSG_PROMISE_RESOLVED_WITH_ITSELF, 0, JSEXN_TYPEERR, "A promise cannot be resolved with itself") -MSG_DEF(JSMSG_SETTIMEOUT_INTERVAL_NONZERO, 0, JSEXN_TYPEERR, "Intervals other than 0 are not supported") - // Modules MSG_DEF(JSMSG_BAD_DEFAULT_EXPORT, 0, JSEXN_SYNTAXERR, "default export cannot be provided by export *") MSG_DEF(JSMSG_MISSING_INDIRECT_EXPORT, 0, JSEXN_SYNTAXERR, "indirect export not found") diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index bc931268220d..6e89e4b8cbe0 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -944,12 +944,7 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool bodyOnly, bool lamb return nullptr; } if (!fun->isArrow()) { - bool ok; - if (fun->isStarGenerator()) - ok = out.append("function* "); - else - ok = out.append("function "); - if (!ok) + if (!(fun->isStarGenerator() ? out.append("function* ") : out.append("function "))) return nullptr; } if (fun->atom()) { diff --git a/js/src/jsfun.h b/js/src/jsfun.h index 5ff6ed859222..cde4e2ee88c9 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -285,13 +285,6 @@ class JSFunction : public js::NativeObject flags_ |= RESOLVED_NAME; } - void setAsyncKind(js::FunctionAsyncKind asyncKind) { - if (isInterpretedLazy()) - lazyScript()->setAsyncKind(asyncKind); - else - nonLazyScript()->setAsyncKind(asyncKind); - } - JSAtom* atom() const { return hasGuessedAtom() ? nullptr : atom_.get(); } js::PropertyName* name() const { @@ -466,18 +459,12 @@ class JSFunction : public js::NativeObject return js::NotGenerator; } - js::FunctionAsyncKind asyncKind() const { - return isInterpretedLazy() ? lazyScript()->asyncKind() : nonLazyScript()->asyncKind(); - } - bool isGenerator() const { return generatorKind() != js::NotGenerator; } bool isLegacyGenerator() const { return generatorKind() == js::LegacyGenerator; } bool isStarGenerator() const { return generatorKind() == js::StarGenerator; } - bool isAsync() const { return asyncKind() == js::AsyncFunction; } - void setScript(JSScript* script_) { mutableScript() = script_; } diff --git a/js/src/jsprototypes.h b/js/src/jsprototypes.h index c3eac76ae0d6..e9e413ebef10 100644 --- a/js/src/jsprototypes.h +++ b/js/src/jsprototypes.h @@ -56,12 +56,6 @@ #define IF_SAB(real,imaginary) imaginary #endif -#ifdef NIGHTLY_BUILD -#define IF_NIGHTLY(real,imaginary) real -#else -#define IF_NIGHTLY(real,imaginary) imaginary -#endif - #define JS_FOR_PROTOTYPES(real,imaginary) \ imaginary(Null, 0, InitNullClass, dummy) \ real(Object, 1, InitViaClassSpec, OCLASP(Plain)) \ @@ -121,7 +115,6 @@ IF_SAB(real,imaginary)(Atomics, 53, InitAtomicsClass, OCLASP real(Module, 55, InitModuleClass, OCLASP(Module)) \ real(ImportEntry, 56, InitImportEntryClass, OCLASP(ImportEntry)) \ real(ExportEntry, 57, InitExportEntryClass, OCLASP(ExportEntry)) \ -IF_NIGHTLY(real, imaginary)(ShellPromise, 58, InitViaClassSpec, OCLASP(ShellPromise)) \ #define JS_FOR_EACH_PROTOTYPE(macro) JS_FOR_PROTOTYPES(macro,macro) diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 923b10851bbb..3c8d26b889f7 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -2759,7 +2759,6 @@ JSScript::linkToFunctionFromEmitter(js::ExclusiveContext* cx, JS::HandleisGeneratorExp_ = funbox->inGenexpLambda; script->setGeneratorKind(funbox->generatorKind()); - script->setAsyncKind(funbox->asyncKind()); // Link the function and the script to each other, so that StaticScopeIter // may walk the scope chain of currently compiling scripts. @@ -2850,7 +2849,6 @@ JSScript::fullyInitFromEmitter(ExclusiveContext* cx, HandleScript script, Byteco MOZ_ASSERT(script->functionNonDelazifying() == funbox->function()); MOZ_ASSERT(script->isGeneratorExp_ == funbox->inGenexpLambda); MOZ_ASSERT(script->generatorKind() == funbox->generatorKind()); - MOZ_ASSERT(script->asyncKind() == funbox->asyncKind()); } else { MOZ_ASSERT(!script->funHasExtensibleScope_); MOZ_ASSERT(!script->funNeedsDeclEnvObject_); diff --git a/js/src/jsscript.h b/js/src/jsscript.h index b2d340974aa2..9502897df9fe 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -873,8 +873,6 @@ class ScriptSourceObject : public NativeObject enum GeneratorKind { NotGenerator, LegacyGenerator, StarGenerator }; -enum FunctionAsyncKind { SyncFunction, AsyncFunction }; - static inline unsigned GeneratorKindAsBits(GeneratorKind generatorKind) { return static_cast(generatorKind); @@ -1169,8 +1167,6 @@ class JSScript : public js::gc::TenuredCell bool isDerivedClassConstructor_:1; - bool isAsync_:1; - // Add padding so JSScript is gc::Cell aligned. Make padding protected // instead of private to suppress -Wunused-private-field compiler warnings. protected: @@ -1437,12 +1433,6 @@ class JSScript : public js::gc::TenuredCell generatorKindBits_ = GeneratorKindAsBits(kind); } - js::FunctionAsyncKind asyncKind() const { return isAsync_ ? js::AsyncFunction : js::SyncFunction; } - - void setAsyncKind(js::FunctionAsyncKind kind) { - isAsync_ = kind == js::AsyncFunction; - } - void setNeedsHomeObject() { needsHomeObject_ = true; } @@ -2109,11 +2099,11 @@ class LazyScript : public gc::TenuredCell // Assorted bits that should really be in ScriptSourceObject. uint32_t version : 8; - uint32_t numFreeVariables : 23; + uint32_t numFreeVariables : 24; uint32_t numInnerFunctions : 20; uint32_t generatorKindBits : 2; - uint32_t isAsync : 1; + // N.B. These are booleans but need to be uint32_t to pack correctly on MSVC. // If you add another boolean here, make sure to initialze it in // LazyScript::CreateRaw(). @@ -2226,10 +2216,6 @@ class LazyScript : public gc::TenuredCell GeneratorKind generatorKind() const { return GeneratorKindFromBits(p_.generatorKindBits); } - FunctionAsyncKind asyncKind() const { return p_.isAsync ? AsyncFunction : SyncFunction; } - - void setAsyncKind(FunctionAsyncKind kind) { p_.isAsync = kind == AsyncFunction; } - bool isGenerator() const { return generatorKind() != NotGenerator; } bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; } diff --git a/js/src/jsversion.h b/js/src/jsversion.h index 614ce255105e..59fbc3815ce3 100644 --- a/js/src/jsversion.h +++ b/js/src/jsversion.h @@ -46,9 +46,6 @@ /* Support for ES7 Exponentiation proposal. */ #define JS_HAS_EXPONENTIATION 1 -/* Support for ES7 Async Functions. */ -#define JS_HAS_ASYNC_FUNCS 1 - #endif // NIGHTLY_BUILD #endif /* jsversion_h */ diff --git a/js/src/moz.build b/js/src/moz.build index 779794bb06ac..cf811a13d080 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -152,7 +152,6 @@ UNIFIED_SOURCES += [ 'builtin/ModuleObject.cpp', 'builtin/Object.cpp', 'builtin/Profilers.cpp', - 'builtin/Promise.cpp', 'builtin/Reflect.cpp', 'builtin/ReflectParse.cpp', 'builtin/SIMD.cpp', diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 2000b727125c..4897f29003bb 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -1536,68 +1536,6 @@ PrintErr(JSContext* cx, unsigned argc, Value* vp) return PrintInternal(cx, args, gErrFile); } -static bool -SetTimeout(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - - if (args.length() < 2) { - JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED, - "setTimeout", args.length() == 0 ? "0" : "1", "s"); - return false; - } - - RootedValue rval(cx); - JS::AutoValueVector argValues(cx); - argValues.append(args.get(0)); - argValues.append(args.get(1)); - HandleValueArray arr(argValues); - - JSAtom* setTimeoutAtom; - if (!(setTimeoutAtom = Atomize(cx, "setTimeout", 10))) - return false; - - RootedPropertyName name(cx, setTimeoutAtom->asPropertyName()); - RootedValue selfHostedFun(cx); - - if (!GlobalObject::getIntrinsicValue(cx, cx->global(), name, &selfHostedFun)) - return false; - - RootedObject undef(cx); - if (!JS_CallFunctionValue(cx, undef, selfHostedFun, arr, &rval)) - return false; - - args.rval().set(rval); - return true; -} - -static bool -RunEvents(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - - RootedValue rval(cx); - JS::AutoValueVector argValues(cx); - HandleValueArray arr(argValues); - - JSAtom* runEvents; - if (!(runEvents = Atomize(cx, "runEvents", 9))) - return false; - - RootedPropertyName name(cx, runEvents->asPropertyName()); - RootedValue selfHostedFun(cx); - - if (!GlobalObject::getIntrinsicValue(cx, cx->global(), name, &selfHostedFun)) - return false; - - RootedObject undef(cx); - if (!JS_CallFunctionValue(cx, undef, selfHostedFun, arr, &rval)) - return false; - - args.rval().set(rval); - return true; -} - static bool Help(JSContext* cx, unsigned argc, Value* vp); @@ -4658,15 +4596,6 @@ static const JSFunctionSpecWithHelp shell_functions[] = { "dateNow()", " Return the current time with sub-ms precision."), - JS_FN_HELP("setTimeout", SetTimeout, 2, 2, -"setTimeout(fn, timeout)", -" Execute a function after a specified timeout. Currently only 0 is supported."), - - JS_FN_HELP("runEvents", RunEvents, 2, 2, -"runEvents()", -" Run events that were scheduled using setTimeout() calls.\n" -" This call is required, because there is no real event loop."), - JS_FN_HELP("help", Help, 0, 0, "help([name ...])", " Display usage and help messages."), diff --git a/js/src/tests/ecma_6/Promise/promise.js b/js/src/tests/ecma_6/Promise/promise.js deleted file mode 100644 index 0698604cd9f9..000000000000 --- a/js/src/tests/ecma_6/Promise/promise.js +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Because there is no way to "wait" for a callback in this testing system, - * there was a need to make one big promise out of all test cases. - */ - -var Promise = ShellPromise; - -Promise.all([ - - assertEventuallyEq(new Promise(resolve => resolve(2)), 2), - - assertEventuallyThrows(new Promise((_, reject) => reject(new Error())), Error), - - assertEventuallyThrows(new Promise(() => { throw new Error(); }), Error), - - assertEventuallyEq(new Promise(resolve => resolve()) - .then(() => 3), 3), - - assertEventuallyEq(new Promise(resolve => resolve()) - .then(() => new Promise(r => r(3))), 3), - - assertEventuallyEq(new Promise((_, reject) => reject(new Error())) - .catch(() => new Promise(r => r(3))), 3), - - assertEventuallyThrows(new Promise(resolve => resolve()) - .then(() => { throw new Error(); }), Error), - - assertEventuallyEq(new Promise((_, reject) => reject(new Error())) - .catch(() => 4), 4), - - assertEventuallyEq(Promise.resolve(5), 5), - - assertEventuallyThrows(Promise.reject(new Error()), Error), - - assertEventuallyDeepEq(Promise.all([]), []), - - assertEventuallyDeepEq(Promise.all(Array(10).fill() - .map((_, id) => new Promise(resolve => resolve(id)))), - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), - -]) - .then(() => { - if (typeof reportCompare === "function") - reportCompare(true, true); - }); diff --git a/js/src/tests/ecma_6/Promise/security.js b/js/src/tests/ecma_6/Promise/security.js deleted file mode 100644 index 6971e3976430..000000000000 --- a/js/src/tests/ecma_6/Promise/security.js +++ /dev/null @@ -1,12 +0,0 @@ -var Promise = ShellPromise; - -var oldThen = Promise.prototype.then; - -// Changing then() should not break catch() -Promise.prototype.then = function() { throw new Error(); }; - -new Promise(a => { throw new Error(); }) - .catch(() => { - if (typeof reportCompare === "function") - reportCompare(true, true); - }); diff --git a/js/src/tests/ecma_6/Promise/shell.js b/js/src/tests/ecma_6/Promise/shell.js deleted file mode 100644 index c15a30f2ac7e..000000000000 --- a/js/src/tests/ecma_6/Promise/shell.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * These functions are inspired by chai-as-promised library for promise testing - * in JS applications. They check if promises eventually resolve to a given value - * or are rejected with a specified error type. - */ - -if (typeof assertEventuallyEq === 'undefined') { - assertEventuallyEq = function(promise, expected) { - return promise.then(actual => assertEq(actual, expected)); - }; -} - -if (typeof assertEventuallyThrows === 'undefined') { - assertEventuallyThrows = function(promise, expectedErrorType) { - return promise.catch(actualE => assertEq(actualE instanceof expectedErrorType, true)); - }; -} - -if (typeof assertEventuallyDeepEq === 'undefined') { - assertEventuallyDeepEq = function(promise, expected) { - return promise.then(actual => assertDeepEq(actual, expected)); - }; -} diff --git a/js/src/tests/ecma_6/shell.js b/js/src/tests/ecma_6/shell.js index 1d5d37460759..887bb0c015a4 100644 --- a/js/src/tests/ecma_6/shell.js +++ b/js/src/tests/ecma_6/shell.js @@ -215,3 +215,14 @@ if (typeof assertWarning === 'undefined') { disableLastWarning(); } } + +function classesEnabled(testCode = "class Foo { constructor() {} }") { + try { + new Function(testCode); + return true; + } catch (e) { + if (!(e instanceof SyntaxError)) + throw e; + return false; + } +} diff --git a/js/src/tests/ecma_7/AsyncFunctions/1.1.1.js b/js/src/tests/ecma_7/AsyncFunctions/1.1.1.js deleted file mode 100644 index 827ed54563fb..000000000000 --- a/js/src/tests/ecma_7/AsyncFunctions/1.1.1.js +++ /dev/null @@ -1,20 +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/. */ - -function assertThrowsSE(code) { - assertThrows(() => Reflect.parse(code), SyntaxError); -} - -if (asyncFunctionsEnabled()) { - assertThrowsSE("'use strict'; async function eval() {}"); - assertThrowsSE("'use strict'; async function arguments() {}"); - assertThrowsSE("async function a(k = super.prop) { }"); - assertThrowsSE("async function a() { super.prop(); }"); - assertThrowsSE("async function a() { super(); }"); - - assertThrowsSE("async function a(k = await 3) {}"); -} - -if (typeof reportCompare === "function") - reportCompare(true, true); diff --git a/js/src/tests/ecma_7/AsyncFunctions/1.1.2.js b/js/src/tests/ecma_7/AsyncFunctions/1.1.2.js deleted file mode 100644 index c299243e129a..000000000000 --- a/js/src/tests/ecma_7/AsyncFunctions/1.1.2.js +++ /dev/null @@ -1,20 +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 test = ` - -async function test() { } - -var anon = async function() { } - -assertEq(test.name, "test"); -assertEq(anon.name, ""); - -`; - -if (asyncFunctionsEnabled()) - eval(test); - -if (typeof reportCompare === "function") - reportCompare(true, true); diff --git a/js/src/tests/ecma_7/AsyncFunctions/methods.js b/js/src/tests/ecma_7/AsyncFunctions/methods.js deleted file mode 100644 index b749398e67bd..000000000000 --- a/js/src/tests/ecma_7/AsyncFunctions/methods.js +++ /dev/null @@ -1,65 +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 test = ` - -var Promise = ShellPromise; - -class X { - constructor() { - this.value = 42; - } - async getValue() { - return this.value; - } - setValue(value) { - this.value = value; - } - async increment() { - var value = await this.getValue(); - this.setValue(value + 1); - return this.getValue(); - } - async getBaseClassName() { - return 'X'; - } - static async getStaticValue() { - return 44; - } -} - -class Y extends X { - constructor() { } - async getBaseClassName() { - return super.getBaseClassName(); - } -} - -var objLiteral = { - async get() { - return 45; - }, - someStuff: 5 -}; - -var x = new X(); -var y = new Y(); - -Promise.all([ - assertEventuallyEq(x.getValue(), 42), - assertEventuallyEq(x.increment(), 43), - assertEventuallyEq(X.getStaticValue(), 44), - assertEventuallyEq(objLiteral.get(), 45), - assertEventuallyEq(y.getBaseClassName(), 'X'), -]).then(() => { - if (typeof reportCompare === "function") - reportCompare(true, true); -}); - -`; - -if (classesEnabled() && asyncFunctionsEnabled()) - eval(test); -else if (typeof reportCompare === 'function') - reportCompare(0,0,"OK"); diff --git a/js/src/tests/ecma_7/AsyncFunctions/semantics.js b/js/src/tests/ecma_7/AsyncFunctions/semantics.js deleted file mode 100644 index d039e2cb37a3..000000000000 --- a/js/src/tests/ecma_7/AsyncFunctions/semantics.js +++ /dev/null @@ -1,177 +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 test = ` - -var Promise = ShellPromise; - -async function empty() { - -} - -async function simpleReturn() { - return 1; -} - -async function simpleAwait() { - var result = await 2; - return result; -} - -async function simpleAwaitAsync() { - var result = await simpleReturn(); - return 2 + result; -} - -async function returnOtherAsync() { - return 1 + await simpleAwaitAsync(); -} - -async function simpleThrower() { - throw new Error(); -} - -async function delegatedThrower() { - var val = await simpleThrower(); - return val; -} - -async function tryCatch() { - try { - await delegatedThrower(); - return 'FAILED'; - } catch (_) { - return 5; - } -} - -async function tryCatchThrow() { - try { - await delegatedThrower(); - return 'FAILED'; - } catch (_) { - return delegatedThrower(); - } -} - -async function wellFinally() { - try { - await delegatedThrower(); - } catch (_) { - return 'FAILED'; - } finally { - return 6; - } -} - -async function finallyMayFail() { - try { - await delegatedThrower(); - } catch (_) { - return 5; - } finally { - return delegatedThrower(); - } -} - -async function embedded() { - async function inner() { - return 7; - } - return await inner(); -} - -// recursion, it works! -async function fib(n) { - return (n == 0 || n == 1) ? n : await fib(n - 1) + await fib(n - 2); -} - -// mutual recursion -async function isOdd(n) { - async function isEven(n) { - return n === 0 || await isOdd(n - 1); - } - return n !== 0 && await isEven(n - 1); -} - -// recursion, take three! -var hardcoreFib = async function fib2(n) { - return (n == 0 || n == 1) ? n : await fib2(n - 1) + await fib2(n - 2); -} - -var asyncExpr = async function() { - return 10; -} - -var namedAsyncExpr = async function simple() { - return 11; -} - -async function executionOrder() { - var value = 0; - async function first() { - return (value = value === 0 ? 1 : value); - } - async function second() { - return (value = value === 0 ? 2 : value); - } - async function third() { - return (value = value === 0 ? 3 : value); - } - return await first() + await second() + await third() + 6; -} - -async function miscellaneous() { - if (arguments.length === 3 && - arguments.callee.name === "miscellaneous") - return 14; -} - -function thrower() { - throw 15; -} - -async function defaultArgs(arg = thrower()) { - -} - -// Async functions are not constructible -assertThrows(() => { - async function Person() { - - } - new Person(); -}, TypeError); - -Promise.all([ - assertEventuallyEq(empty(), undefined), - assertEventuallyEq(simpleReturn(), 1), - assertEventuallyEq(simpleAwait(), 2), - assertEventuallyEq(simpleAwaitAsync(), 3), - assertEventuallyEq(returnOtherAsync(), 4), - assertEventuallyThrows(simpleThrower(), Error), - assertEventuallyEq(tryCatch(), 5), - assertEventuallyThrows(tryCatchThrow(), Error), - assertEventuallyEq(wellFinally(), 6), - assertEventuallyThrows(finallyMayFail(), Error), - assertEventuallyEq(embedded(), 7), - assertEventuallyEq(fib(6), 8), - assertEventuallyEq(executionOrder(), 9), - assertEventuallyEq(asyncExpr(), 10), - assertEventuallyEq(namedAsyncExpr(), 11), - assertEventuallyEq(isOdd(12).then(v => v ? "oops" : 12), 12), - assertEventuallyEq(hardcoreFib(7), 13), - assertEventuallyEq(miscellaneous(1, 2, 3), 14), - assertEventuallyEq(defaultArgs().catch(e => e), 15) -]).then(() => { - if (typeof reportCompare === "function") - reportCompare(true, true); -}); - -`; - -if (asyncFunctionsEnabled()) - eval(test); -else if (typeof reportCompare === 'function') - reportCompare(0,0,"OK"); diff --git a/js/src/tests/ecma_7/AsyncFunctions/shell.js b/js/src/tests/ecma_7/AsyncFunctions/shell.js deleted file mode 100644 index bedaac504195..000000000000 --- a/js/src/tests/ecma_7/AsyncFunctions/shell.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/. */ - -/** - * These methods are inspired by chai-as-promised library for promise testing - * in JS applications. They check if promises eventually resolve to a given value - * or are rejected with a specified error type. - */ - -if (typeof assertEventuallyEq === 'undefined') { - assertEventuallyEq = function(promise, expected) { - return promise.then(actual => assertEq(actual, expected)); - }; -} - -if (typeof assertEventuallyThrows === 'undefined') { - assertEventuallyThrows = function(promise, expectedErrorType) { - return promise.catch(actualE => assertEq(actualE instanceof expectedErrorType, true)); - }; -} - -if (typeof assertEventuallyDeepEq === 'undefined') { - assertEventuallyDeepEq = function(promise, expected) { - return promise.then(actual => assertDeepEq(actual, expected)); - }; -} - -function asyncFunctionsEnabled() { - try { - eval("async function f() { }"); - return true; - } catch (e if e instanceof SyntaxError) { - return false; - } -} diff --git a/js/src/tests/ecma_7/AsyncFunctions/syntax-modules.js b/js/src/tests/ecma_7/AsyncFunctions/syntax-modules.js deleted file mode 100644 index f3d666b71f01..000000000000 --- a/js/src/tests/ecma_7/AsyncFunctions/syntax-modules.js +++ /dev/null @@ -1,10 +0,0 @@ -if (asyncFunctionsEnabled()) { - parseModule("async function f() { await 3; }"); - parseModule("async function f() { await 3; }"); - assertThrows(() => parseModule("var await = 5;"), SyntaxError); - assertThrows(() => parseModule("export var await;"), SyntaxError); - assertThrows(() => parseModule("async function f() { function g() { await 3; } }"), SyntaxError); -} - -if (typeof reportCompare === "function") - reportCompare(true, true); diff --git a/js/src/tests/ecma_7/AsyncFunctions/syntax.js b/js/src/tests/ecma_7/AsyncFunctions/syntax.js deleted file mode 100644 index 5723fa5a3a7b..000000000000 --- a/js/src/tests/ecma_7/AsyncFunctions/syntax.js +++ /dev/null @@ -1,87 +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/. */ - -/** - * Currently only a part of async/await grammar is supported: - * - Async function statements are supported. - * - Await expressions are supported (as regular unary expressions). - * All other parts of proposal are probably not supported. - * Even the supported parts of implementation may not be 100% compliant with - * the grammar. This is to be considered a proof-of-concept implementation. - */ - -if (asyncFunctionsEnabled()) { - assertEq(Reflect.parse("function a() {}").body[0].async, false); - assertEq(Reflect.parse("function* a() {}").body[0].async, false); - assertEq(Reflect.parse("async function a() {}").body[0].async, true); - assertEq(Reflect.parse("() => {}").body[0].async, undefined); - - // Async generators are not allowed (with regards to spec) - assertThrows(() => Reflect.parse("async function* a() {}"), SyntaxError); - - // No line terminator after async - assertEq(Reflect.parse("async\nfunction a(){}").body[0].expression.name, "async"); - - // Async arrow functions are allowed, but not supported yet - assertThrows(() => Reflect.parse("async () => true"), SyntaxError); - - // Async function expressions - assertEq(Reflect.parse("(async function() {})()").body[0].expression.callee.async, true); - assertEq(Reflect.parse("var k = async function() {}").body[0].declarations[0].init.async, true); - assertEq(Reflect.parse("var nmd = async function named() {}").body[0].declarations[0].init.id.name, "named"); - - // Awaiting not directly inside an async function is not allowed - assertThrows(() => Reflect.parse("await 4;"), SyntaxError); - assertThrows(() => Reflect.parse("function a() { await 4; }"), SyntaxError); - assertThrows(() => Reflect.parse("function* a() { await 4; }"), SyntaxError); - assertThrows(() => Reflect.parse("async function k() { function a() { await 4; } }"), SyntaxError); - - // No line terminator after await is allowed - assertThrows(() => Reflect.parse("async function a() { await\n4; }"), SyntaxError); - - // Await is not allowed as a default expr. - assertThrows(() => Reflect.parse("async function a(k = await 3) {}"), SyntaxError); - assertThrows(() => Reflect.parse("async function a() { async function b(k = await 3) {} }"), SyntaxError); - - // Await is not legal as an identifier in an async function. - assertThrows(() => Reflect.parse("async function a() { var await = 4; }"), SyntaxError); - assertThrows(() => Reflect.parse("async function a() { return await; }"), SyntaxError); - - // Yield is not allowed in an async function / treated as identifier - assertThrows(() => Reflect.parse("async function a() { yield 3; }"), SyntaxError); - - // Await is still available as an identifier name in strict mode code. - Reflect.parse("function a() { 'use strict'; var await = 3; }"); - Reflect.parse("'use strict'; var await = 3;"); - - // Await is treated differently depending on context. Various cases. - Reflect.parse("var await = 3; async function a() { await 4; }"); - Reflect.parse("async function a() { await 4; } var await = 5"); - Reflect.parse("async function a() { function b() { return await; } }") - - Reflect.parse("async function a() { var k = { async: 4 } }"); - - Reflect.parse("function a() { await: 4 }"); - - assertEq(Reflect.parse("async function a() { await 4; }") - .body[0].body.body[0].expression.operator, "await"); - - assertEq(Reflect.parse("async function a() { async function b() { await 4; } }") - .body[0].body.body[0].body.body[0].expression.operator, "await"); - - // operator priority test - assertEq(Reflect.parse("async function a() { await 2 + 3; }") - .body[0].body.body[0].expression.left.argument.value, 2); - assertEq(Reflect.parse("async function a() { await 2 + 3; }") - .body[0].body.body[0].expression.left.operator, "await"); - assertEq(Reflect.parse("async function a() { await 2 + 3; }") - .body[0].body.body[0].expression.right.value, 3); - - // blocks and other constructions - assertEq(Reflect.parse("{ async function a() { return 2; } }") - .body[0].body[0].async, true); -} - -if (typeof reportCompare === "function") - reportCompare(true, true); diff --git a/js/src/tests/shell.js b/js/src/tests/shell.js index daf75716d41d..a2021e90e27b 100644 --- a/js/src/tests/shell.js +++ b/js/src/tests/shell.js @@ -872,17 +872,6 @@ function assertThrowsInstanceOf(f, ctor, msg) { throw new Error(fullmsg); }; -function classesEnabled(testCode = "class Foo { constructor() {} }") { - try { - new Function(testCode); - return true; - } catch (e) { - if (!(e instanceof SyntaxError)) - throw e; - return false; - } -} - /* * Some tests need to know if we are in Rhino as opposed to SpiderMonkey */ diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index e045462e935b..ca6eb3658391 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -18,8 +18,6 @@ macro(apply, apply, "apply") \ macro(arguments, arguments, "arguments") \ macro(as, as, "as") \ - macro(async, async, "async") \ - macro(await, await, "await") \ macro(ArrayIteratorNext, ArrayIteratorNext, "ArrayIteratorNext") \ macro(ArrayType, ArrayType, "ArrayType") \ macro(ArrayValues, ArrayValues, "ArrayValues") \ diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index f56aaf083713..cce3fcd68127 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -23,11 +23,6 @@ #include "builtin/MapObject.h" #include "builtin/ModuleObject.h" #include "builtin/Object.h" - -#ifdef NIGHTLY_BUILD -#include "builtin/Promise.h" -#endif - #include "builtin/RegExp.h" #include "builtin/SIMD.h" #include "builtin/SymbolObject.h" diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index 6b31fbaa8497..68a9e621ebe4 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -382,12 +382,6 @@ class GlobalObject : public NativeObject return &global->getPrototype(JSProto_Symbol).toObject().as(); } - static NativeObject* getOrCreatePromisePrototype(JSContext* cx, Handle global) { - if (!ensureConstructor(cx, global, JSProto_ShellPromise)) - return nullptr; - return &global->getPrototype(JSProto_ShellPromise).toObject().as(); - } - static NativeObject* getOrCreateRegExpPrototype(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_RegExp)) return nullptr; diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 061a4850fb79..5a32a10e138d 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -3507,18 +3507,17 @@ CASE(JSOP_DEFVAR) } END_CASE(JSOP_DEFVAR) -CASE(JSOP_DEFFUN) { +CASE(JSOP_DEFFUN) +{ /* * A top-level function defined in Global or Eval code (see ECMA-262 * Ed. 3), or else a SpiderMonkey extension: a named function statement in * a compound statement (not at the top statement level of global code, or * at the top level of a function body). */ - MOZ_ASSERT(REGS.sp[-1].isObject()); - ReservedRooted fun(&rootFunction0, ®S.sp[-1].toObject().as()); + ReservedRooted fun(&rootFunction0, script->getFunction(GET_UINT32_INDEX(REGS.pc))); if (!DefFunOperation(cx, script, REGS.fp()->scopeChain(), fun)) goto error; - REGS.sp--; } END_CASE(JSOP_DEFFUN) @@ -4322,6 +4321,14 @@ js::DefFunOperation(JSContext* cx, HandleScript script, HandleObject scopeChain, * requests in server-side JS. */ RootedFunction fun(cx, funArg); + if (fun->isNative() || fun->environment() != scopeChain) { + fun = CloneFunctionObjectIfNotSingleton(cx, fun, scopeChain, nullptr, TenuredObject); + if (!fun) + return false; + } else { + MOZ_ASSERT(script->treatAsRunOnce()); + MOZ_ASSERT(!script->functionNonDelazifying()); + } /* * We define the function as a property of the variable object and not the diff --git a/js/src/vm/Keywords.h b/js/src/vm/Keywords.h index db599274c871..4c9e1729a0c8 100644 --- a/js/src/vm/Keywords.h +++ b/js/src/vm/Keywords.h @@ -56,7 +56,6 @@ macro(protected, protected_, TOK_STRICT_RESERVED, JSVERSION_DEFAULT) \ macro(public, public_, TOK_STRICT_RESERVED, JSVERSION_DEFAULT) \ macro(static, static_, TOK_STRICT_RESERVED, JSVERSION_DEFAULT) \ - macro(await, await, TOK_AWAIT, JSVERSION_DEFAULT) \ /* \ * Yield is a token inside function*. Outside of a function*, it is a \ * future reserved keyword in strict mode, but a keyword in JS1.7 even \ diff --git a/js/src/vm/Opcodes.h b/js/src/vm/Opcodes.h index 766278e2d46a..fc5d0e0a791e 100644 --- a/js/src/vm/Opcodes.h +++ b/js/src/vm/Opcodes.h @@ -1294,7 +1294,7 @@ * Operands: uint32_t funcIndex * Stack: => */ \ - macro(JSOP_DEFFUN, 127,"deffun", NULL, 1, 1, 0, JOF_BYTE) \ + macro(JSOP_DEFFUN, 127,"deffun", NULL, 5, 0, 0, JOF_OBJECT) \ /* * Defines the new binding on the frame's current variables-object (the * scope object on the scope chain designated to receive new variables) with @@ -1983,6 +1983,7 @@ * Stack: val => ToString(val) */ \ macro(JSOP_TOSTRING, 228, "tostring", NULL, 1, 1, 1, JOF_BYTE) + /* * In certain circumstances it may be useful to "pad out" the opcode space to * a power of two. Use this macro to do so. diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 8ef58d00cace..9af4614a485d 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -237,12 +237,7 @@ CallObject::createForFunction(JSContext* cx, HandleObject enclosing, HandleFunct * object holding function's name. */ if (callee->isNamedLambda()) { - if (callee->isAsync()) { - RootedFunction fun(cx, &callee->getExtendedSlot(1).toObject().as()); - scopeChain = DeclEnvObject::create(cx, scopeChain, fun); - } else { - scopeChain = DeclEnvObject::create(cx, scopeChain, callee); - } + scopeChain = DeclEnvObject::create(cx, scopeChain, callee); if (!scopeChain) return nullptr; } diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 9aaa6498d209..147131081b5d 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -23,7 +23,6 @@ #include "builtin/MapObject.h" #include "builtin/ModuleObject.h" #include "builtin/Object.h" -#include "builtin/Promise.h" #include "builtin/Reflect.h" #include "builtin/SelfHostingDefines.h" #include "builtin/SIMD.h" @@ -442,54 +441,6 @@ intrinsic_GetIteratorPrototype(JSContext* cx, unsigned argc, Value* vp) return true; } -static bool -intrinsic_NewPromise(JSContext* cx, unsigned argc, Value* vp) -{ - return js::PromiseConstructor(cx, argc, vp); -} - -static bool -intrinsic_IsPromise(JSContext* cx, unsigned argc, Value* vp) { - CallArgs args = CallArgsFromVp(argc, vp); - MOZ_ASSERT(args.length() == 1); - MOZ_ASSERT(args[0].isObject()); - bool isPromise = args[0].toObject().getClass() == &ShellPromiseObject::class_; - - args.rval().setBoolean(isPromise); - return true; -} - -static bool -intrinsic_SetFunName(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - MOZ_ASSERT(args.length() == 2); - MOZ_ASSERT(args[0].isObject() && args[0].toObject().is()); - MOZ_ASSERT(args[1].isString()); - JSAtom* atom = AtomizeString(cx, args[1].toString()); - if (atom == nullptr) - return false; - RootedFunction fun(cx, &args[0].toObject().as()); - fun->setFlags(fun->flags() & ~JSFunction::HAS_GUESSED_ATOM); - fun->initAtom(atom); - - return true; -} - -static bool -intrinsic_GetFunName(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - MOZ_ASSERT(args.length() == 1); - MOZ_ASSERT(args[0].isObject() && args[0].toObject().is()); - PropertyName* name = args[0].toObject().as().name(); - if (!name) - args.rval().setUndefined(); - else - args.rval().setString(name); - return true; -} - static bool intrinsic_NewArrayIterator(JSContext* cx, unsigned argc, Value* vp) { @@ -1243,20 +1194,6 @@ intrinsic_IsWeakSet(JSContext* cx, unsigned argc, Value* vp) return true; } -bool -intrinsic_SetFunctionExtendedSlot(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - MOZ_ASSERT(args.length() == 3); - MOZ_ASSERT(args[0].isObject()); - MOZ_ASSERT(args[0].toObject().is()); - MOZ_ASSERT(args[1].isInt32()); - - args[0].toObject().as().setExtendedSlot(args[1].toPrivateUint32(), args[2]); - args.rval().setUndefined(); - return true; -} - /** * Returns the default locale as a well-formed, but not necessarily canonicalized, * BCP-47 language tag. @@ -1496,7 +1433,6 @@ static const JSFunctionSpec intrinsic_functions[] = { JS_FN("_ConstructorForTypedArray", intrinsic_ConstructorForTypedArray, 1,0), JS_FN("DecompileArg", intrinsic_DecompileArg, 2,0), JS_FN("RuntimeDefaultLocale", intrinsic_RuntimeDefaultLocale, 0,0), - JS_FN("SetFunctionExtendedSlot", intrinsic_SetFunctionExtendedSlot, 3,0), JS_FN("LocalTZA", intrinsic_LocalTZA, 0,0), JS_INLINABLE_FN("_IsConstructing", intrinsic_IsConstructing, 0,0, @@ -1584,11 +1520,7 @@ static const JSFunctionSpec intrinsic_functions[] = { CallNonGenericSelfhostedMethod>, 2, 0), JS_FN("IsWeakSet", intrinsic_IsWeakSet, 1,0), - JS_FN("NewPromise", intrinsic_NewPromise, 1,0), - JS_FN("IsPromise", intrinsic_IsPromise, 1,0), - JS_FN("SetFunName", intrinsic_SetFunName, 2,0), - JS_FN("GetFunName", intrinsic_GetFunName, 1,0), // See builtin/TypedObject.h for descriptors of the typedobj functions. JS_FN("NewOpaqueTypedObject", js::NewOpaqueTypedObject, 1, 0), JS_FN("NewDerivedTypedObject", js::NewDerivedTypedObject, 3, 0), diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h index dbb4fc8bf62b..e65fc7cb8b13 100644 --- a/js/src/vm/Xdr.h +++ b/js/src/vm/Xdr.h @@ -29,11 +29,11 @@ namespace js { * * https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode */ -static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 311; +static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 310; static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND); -static_assert(JSErr_Limit == 425, +static_assert(JSErr_Limit == 415, "GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or " "removed MSG_DEFs from js.msg, you should increment " "XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's " From 2bba95670b2c7d954345faa6a9912a84d6f2f995 Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Wed, 3 Sep 2014 11:09:30 -0700 Subject: [PATCH 040/228] Bug 977338 - Smaller unified chunks for js/src, r=terrence --HG-- extra : commitid : 84tRIEZntfN extra : rebase_source : e78cd43949ef6e7b9e9ce03db284914b727cb7d1 --- js/src/moz.build | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/src/moz.build b/js/src/moz.build index cf811a13d080..79c1110adf39 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -11,6 +11,8 @@ component_intl = ('Core', 'JavaScript: Internationalization API') component_jit = ('Core', 'JavaScript Engine: JIT') component_stl = ('Core', 'JavaScript: Standard Library') +FILES_PER_UNIFIED_FILE = 6 + with Files('../public/**'): BUG_COMPONENT = component_engine with Files('*'): From 21d25edc6c429656e26761102446ae119b4bb8ba Mon Sep 17 00:00:00 2001 From: Ben Hsu Date: Wed, 2 Sep 2015 05:21:00 +0200 Subject: [PATCH 041/228] Bug 1171807 - Part 1: Add enums for TelephonyCall::State and TelephonyCallGroup::State (WebIDL). r=hsinyi --- dom/webidl/TelephonyCall.webidl | 11 ++++++++++- dom/webidl/TelephonyCallGroup.webidl | 8 +++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/dom/webidl/TelephonyCall.webidl b/dom/webidl/TelephonyCall.webidl index 9a529c1297b5..7a44866ed513 100644 --- a/dom/webidl/TelephonyCall.webidl +++ b/dom/webidl/TelephonyCall.webidl @@ -15,7 +15,7 @@ interface TelephonyCall : EventTarget { // call. We need an additional attribute for the CDMA waiting call. readonly attribute TelephonyCallId? secondId; - readonly attribute DOMString state; + readonly attribute TelephonyCallState state; // The property "emergency" indicates whether the call number is an emergency // number. Only the outgoing call could have a value with true and it is @@ -56,6 +56,15 @@ interface TelephonyCall : EventTarget { attribute EventHandler ongroupchange; }; +enum TelephonyCallState { + "dialing", + "alerting", + "connected", + "held", + "disconnected", + "incoming", +}; + enum TelephonyCallDisconnectedReason { "BadNumber", "NoRouteToDestination", diff --git a/dom/webidl/TelephonyCallGroup.webidl b/dom/webidl/TelephonyCallGroup.webidl index fbb8b9d12622..e5af4083094c 100644 --- a/dom/webidl/TelephonyCallGroup.webidl +++ b/dom/webidl/TelephonyCallGroup.webidl @@ -26,7 +26,7 @@ interface TelephonyCallGroup : EventTarget { [NewObject, Throws] Promise resume(); - readonly attribute DOMString state; + readonly attribute TelephonyCallGroupState state; attribute EventHandler onstatechange; attribute EventHandler onconnected; @@ -34,3 +34,9 @@ interface TelephonyCallGroup : EventTarget { attribute EventHandler oncallschanged; attribute EventHandler onerror; }; + +enum TelephonyCallGroupState { + "", + "connected", + "held", +}; From 28c4c83c60fb784ba0c5dfcc7e6c3cdf282afd6e Mon Sep 17 00:00:00 2001 From: Ho-Pang Hsu Date: Tue, 6 Oct 2015 19:11:00 +0200 Subject: [PATCH 042/228] Bug 1171807 - Part 2: Move to enums and deprecate TelephonyCall.mCallState and TelephonyCallGroup.mCallState (DOM). r=btseng --- dom/telephony/Telephony.cpp | 148 +++++++++---------- dom/telephony/Telephony.h | 13 +- dom/telephony/TelephonyCall.cpp | 181 ++++++++++++++--------- dom/telephony/TelephonyCall.h | 37 +++-- dom/telephony/TelephonyCallGroup.cpp | 189 +++++++++++++++--------- dom/telephony/TelephonyCallGroup.h | 31 ++-- dom/telephony/TelephonyDialCallback.cpp | 2 +- 7 files changed, 348 insertions(+), 253 deletions(-) diff --git a/dom/telephony/Telephony.cpp b/dom/telephony/Telephony.cpp index 3a4a967d17e5..1b544f394168 100644 --- a/dom/telephony/Telephony.cpp +++ b/dom/telephony/Telephony.cpp @@ -166,14 +166,6 @@ Telephony::IsValidServiceId(uint32_t aServiceId) return aServiceId < GetNumServices(); } -// static -bool -Telephony::IsActiveState(uint16_t aCallState) { - return aCallState == nsITelephonyService::CALL_STATE_DIALING || - aCallState == nsITelephonyService::CALL_STATE_ALERTING || - aCallState == nsITelephonyService::CALL_STATE_CONNECTED; -} - uint32_t Telephony::GetServiceId(const Optional& aServiceId, bool aGetIfActiveCall) @@ -182,11 +174,11 @@ Telephony::GetServiceId(const Optional& aServiceId, return aServiceId.Value(); } else if (aGetIfActiveCall) { nsTArray > &calls = mCalls; - if (mGroup->CallState() == nsITelephonyService::CALL_STATE_CONNECTED) { + if (mGroup->IsActive()) { calls = mGroup->CallsArray(); } for (uint32_t i = 0; i < calls.Length(); i++) { - if (IsActiveState(calls[i]->CallState())) { + if (calls[i]->IsActive()) { return calls[i]->mServiceId; } } @@ -257,17 +249,17 @@ Telephony::CreateCallId(const nsAString& aNumber, uint16_t aNumberPresentation, already_AddRefed Telephony::CreateCall(TelephonyCallId* aId, uint32_t aServiceId, - uint32_t aCallIndex, uint16_t aCallState, + uint32_t aCallIndex, TelephonyCallState aState, bool aEmergency, bool aConference, bool aSwitchable, bool aMergeable) { // We don't have to create an already ended call. - if (aCallState == nsITelephonyService::CALL_STATE_DISCONNECTED) { + if (aState == TelephonyCallState::Disconnected) { return nullptr; } nsRefPtr call = - TelephonyCall::Create(this, aId, aServiceId, aCallIndex, aCallState, + TelephonyCall::Create(this, aId, aServiceId, aCallIndex, aState, aEmergency, aConference, aSwitchable, aMergeable); NS_ASSERTION(call, "This should never fail!"); @@ -338,61 +330,66 @@ Telephony::HandleCallInfo(nsITelephonyCallInfo* aInfo) aInfo->GetIsSwitchable(&isSwitchable); aInfo->GetIsMergeable(&isMergeable); - nsRefPtr call = GetCallFromEverywhere(serviceId, callIndex); + TelephonyCallState state = TelephonyCall::ConvertToTelephonyCallState(callState); + nsRefPtr call = GetCallFromEverywhere(serviceId, callIndex); + // Handle a newly created call. if (!call) { nsRefPtr id = CreateCallId(aInfo); - call = CreateCall(id, serviceId, callIndex, callState, isEmergency, + call = CreateCall(id, serviceId, callIndex, state, isEmergency, isConference, isSwitchable, isMergeable); - - if (call && callState == nsITelephonyService::CALL_STATE_INCOMING) { + // The newly created call is an incoming call. + if (call && + state == TelephonyCallState::Incoming) { nsresult rv = DispatchCallEvent(NS_LITERAL_STRING("incoming"), call); NS_ENSURE_SUCCESS(rv, rv); } - } else { - call->UpdateEmergency(isEmergency); - call->UpdateSwitchable(isSwitchable); - call->UpdateMergeable(isMergeable); + return NS_OK; + } - nsAutoString number; - aInfo->GetNumber(number); - nsRefPtr id = call->Id(); - id->UpdateNumber(number); + // Update an existing call + call->UpdateEmergency(isEmergency); + call->UpdateSwitchable(isSwitchable); + call->UpdateMergeable(isMergeable); - nsAutoString disconnectedReason; - aInfo->GetDisconnectedReason(disconnectedReason); + nsAutoString number; + aInfo->GetNumber(number); + nsRefPtr id = call->Id(); + id->UpdateNumber(number); - // State changed. - if (call->CallState() != callState) { - if (callState == nsITelephonyService::CALL_STATE_DISCONNECTED) { - call->UpdateDisconnectedReason(disconnectedReason); - call->ChangeState(nsITelephonyService::CALL_STATE_DISCONNECTED); - return NS_OK; - } + nsAutoString disconnectedReason; + aInfo->GetDisconnectedReason(disconnectedReason); - // We don't fire the statechange event on a call in conference here. - // Instead, the event will be fired later in - // TelephonyCallGroup::ChangeState(). Thus the sequence of firing the - // statechange events is guaranteed: first on TelephonyCallGroup then on - // individual TelephonyCall objects. - bool fireEvent = !isConference; - call->ChangeStateInternal(callState, fireEvent); + // State changed. + if (call->State() != state) { + if (state == TelephonyCallState::Disconnected) { + call->UpdateDisconnectedReason(disconnectedReason); + call->ChangeState(TelephonyCallState::Disconnected); + return NS_OK; } - // Group changed. - nsRefPtr group = call->GetGroup(); + // We don't fire the statechange event on a call in conference here. + // Instead, the event will be fired later in + // TelephonyCallGroup::ChangeState(). Thus the sequence of firing the + // statechange events is guaranteed: first on TelephonyCallGroup then on + // individual TelephonyCall objects. + bool fireEvent = !isConference; + call->ChangeStateInternal(state, fireEvent); + } - if (!group && isConference) { - // Add to conference. - NS_ASSERTION(mCalls.Contains(call), "Should in mCalls"); - mGroup->AddCall(call); - RemoveCall(call); - } else if (group && !isConference) { - // Remove from conference. - NS_ASSERTION(mGroup->CallsArray().Contains(call), "Should in mGroup"); - mGroup->RemoveCall(call); - AddCall(call); - } + // Group changed. + nsRefPtr group = call->GetGroup(); + + if (!group && isConference) { + // Add to conference. + NS_ASSERTION(mCalls.Contains(call), "Should in mCalls"); + mGroup->AddCall(call); + RemoveCall(call); + } else if (group && !isConference) { + // Remove from conference. + NS_ASSERTION(mGroup->CallsArray().Contains(call), "Should in mGroup"); + mGroup->RemoveCall(call); + AddCall(call); } return NS_OK; @@ -623,18 +620,21 @@ Telephony::SetSpeakerEnabled(bool aEnabled, ErrorResult& aRv) void Telephony::GetActive(Nullable& aValue) { - if (mGroup->CallState() == nsITelephonyService::CALL_STATE_CONNECTED) { + if (mGroup->IsActive()) { aValue.SetValue().SetAsTelephonyCallGroup() = mGroup; - } else { - // Search the first active call. - for (uint32_t i = 0; i < mCalls.Length(); i++) { - if (IsActiveState(mCalls[i]->CallState())) { - aValue.SetValue().SetAsTelephonyCall() = mCalls[i]; - return; - } - } - aValue.SetNull(); + return; } + + // Search for the active call. + for (uint32_t i = 0; i < mCalls.Length(); i++) { + if (mCalls[i]->IsActive()) { + aValue.SetValue().SetAsTelephonyCall() = mCalls[i]; + return; + } + } + + // Nothing active found. + aValue.SetNull(); } already_AddRefed @@ -747,7 +747,11 @@ Telephony::EnumerateCallState(nsITelephonyCallInfo* aInfo) NS_IMETHODIMP Telephony::ConferenceCallStateChanged(uint16_t aCallState) { - mGroup->ChangeState(aCallState); + // The current design of Telephony Stack gaurantees that the calls within a + // call group are updated before this method being called, so we can let a + // call update its state by its own, and we can discard |aCallState| here. + // Anyway, this method is going to be deprecated in Bug 1155072. + mGroup->ChangeState(); return NS_OK; } @@ -755,19 +759,7 @@ NS_IMETHODIMP Telephony::EnumerateCallStateComplete() { // Set conference state. - if (mGroup->CallsArray().Length() >= 2) { - const nsTArray > &calls = mGroup->CallsArray(); - - uint16_t callState = calls[0]->CallState(); - for (uint32_t i = 1; i < calls.Length(); i++) { - if (calls[i]->CallState() != callState) { - callState = nsITelephonyService::CALL_STATE_UNKNOWN; - break; - } - } - - mGroup->ChangeState(callState); - } + mGroup->ChangeState(); HandleAudioAgentState(); if (mReadyPromise) { diff --git a/dom/telephony/Telephony.h b/dom/telephony/Telephony.h index 241fbf9746c1..8e52958a41cc 100644 --- a/dom/telephony/Telephony.h +++ b/dom/telephony/Telephony.h @@ -190,9 +190,6 @@ private: static bool IsValidServiceId(uint32_t aServiceId); - static bool - IsActiveState(uint16_t aCallState); - uint32_t GetServiceId(const Optional& aServiceId, bool aGetIfActiveCall = false); @@ -212,9 +209,13 @@ private: already_AddRefed CreateCall(TelephonyCallId* aId, - uint32_t aServiceId, uint32_t aCallIndex, uint16_t aCallState, - bool aEmergency = false, bool aConference = false, - bool aSwitchable = true, bool aMergeable = true); + uint32_t aServiceId, + uint32_t aCallIndex, + TelephonyCallState aState, + bool aEmergency = false, + bool aConference = false, + bool aSwitchable = true, + bool aMergeable = true); nsresult NotifyEvent(const nsAString& aType); diff --git a/dom/telephony/TelephonyCall.cpp b/dom/telephony/TelephonyCall.cpp index aa90455f36cd..47c43efb9b78 100644 --- a/dom/telephony/TelephonyCall.cpp +++ b/dom/telephony/TelephonyCall.cpp @@ -34,16 +34,51 @@ } \ } +#ifdef TELEPHONY_CALL_STATE +#undef TELEPHONY_CALL_STATE +#endif + +#define TELEPHONY_CALL_STATE(_state) \ + (TelephonyCallStateValues::strings[static_cast(_state)].value) + using namespace mozilla::dom; using namespace mozilla::dom::telephony; using mozilla::ErrorResult; +// static +TelephonyCallState +TelephonyCall::ConvertToTelephonyCallState(uint32_t aCallState) +{ + switch (aCallState) { + case nsITelephonyService::CALL_STATE_DIALING: + return TelephonyCallState::Dialing; + case nsITelephonyService::CALL_STATE_ALERTING: + return TelephonyCallState::Alerting; + case nsITelephonyService::CALL_STATE_CONNECTED: + return TelephonyCallState::Connected; + case nsITelephonyService::CALL_STATE_HELD: + return TelephonyCallState::Held; + case nsITelephonyService::CALL_STATE_DISCONNECTED: + return TelephonyCallState::Disconnected; + case nsITelephonyService::CALL_STATE_INCOMING: + return TelephonyCallState::Incoming; + } + + NS_NOTREACHED("Unknown state!"); + return TelephonyCallState::Disconnected; +} + // static already_AddRefed -TelephonyCall::Create(Telephony* aTelephony, TelephonyCallId* aId, - uint32_t aServiceId, uint32_t aCallIndex, - uint16_t aCallState, bool aEmergency, bool aConference, - bool aSwitchable, bool aMergeable) +TelephonyCall::Create(Telephony* aTelephony, + TelephonyCallId* aId, + uint32_t aServiceId, + uint32_t aCallIndex, + TelephonyCallState aState, + bool aEmergency, + bool aConference, + bool aSwitchable, + bool aMergeable) { NS_ASSERTION(aTelephony, "Null aTelephony pointer!"); NS_ASSERTION(aId, "Null aId pointer!"); @@ -61,8 +96,7 @@ TelephonyCall::Create(Telephony* aTelephony, TelephonyCallId* aId, call->mMergeable = aMergeable; call->mError = nullptr; - call->ChangeStateInternal(aCallState, false); - + call->ChangeStateInternal(aState, false); return call.forget(); } @@ -83,35 +117,15 @@ TelephonyCall::WrapObject(JSContext* aCx, JS::Handle aGivenProto) } void -TelephonyCall::ChangeStateInternal(uint16_t aCallState, bool aFireEvents) +TelephonyCall::ChangeStateInternal(TelephonyCallState aState, bool aFireEvents) { nsRefPtr kungFuDeathGrip(this); - mCallState = aCallState; - switch (aCallState) { - case nsITelephonyService::CALL_STATE_DIALING: - mState.AssignLiteral("dialing"); - break; - case nsITelephonyService::CALL_STATE_ALERTING: - mState.AssignLiteral("alerting"); - break; - case nsITelephonyService::CALL_STATE_CONNECTED: - mState.AssignLiteral("connected"); - break; - case nsITelephonyService::CALL_STATE_HELD: - mState.AssignLiteral("held"); - break; - case nsITelephonyService::CALL_STATE_DISCONNECTED: - mState.AssignLiteral("disconnected"); - break; - case nsITelephonyService::CALL_STATE_INCOMING: - mState.AssignLiteral("incoming"); - break; - default: - NS_NOTREACHED("Unknown state!"); - } + // Update current state + mState = aState; - if (aCallState == nsITelephonyService::CALL_STATE_DISCONNECTED) { + // Handle disconnected calls + if (mState == TelephonyCallState::Disconnected) { NS_ASSERTION(mLive, "Should be live!"); mLive = false; if (mGroup) { @@ -119,7 +133,7 @@ TelephonyCall::ChangeStateInternal(uint16_t aCallState, bool aFireEvents) } else { mTelephony->RemoveCall(this); } - } else if (!mLive) { + } else if (!mLive) { // Handle newly added calls mLive = true; if (mGroup) { mGroup->AddCall(this); @@ -128,23 +142,39 @@ TelephonyCall::ChangeStateInternal(uint16_t aCallState, bool aFireEvents) } } + // Dispatch call state changed and call state event if (aFireEvents) { - nsresult rv = DispatchCallEvent(NS_LITERAL_STRING("statechange"), this); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to dispatch specific event!"); - } - - // This can change if the statechange handler called back here... Need to - // figure out something smarter. - if (mCallState == aCallState) { - rv = DispatchCallEvent(mState, this); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to dispatch specific event!"); - } - } + NotifyStateChanged(); } } +nsresult +TelephonyCall::NotifyStateChanged() +{ + // Since |mState| can be changed after statechange handler called back here, + // we must save current state. Maybe we should figure out something smarter. + TelephonyCallState prevState = mState; + + nsresult res = DispatchCallEvent(NS_LITERAL_STRING("statechange"), this); + if (NS_FAILED(res)) { + NS_WARNING("Failed to dispatch specific event!"); + } + + // Check whether |mState| remains the same after the statechange handler. + if (mState != prevState) { + NS_WARNING("Call State has changed by statechange handler!"); + return res; + } + + res = DispatchCallEvent(NS_ConvertASCIItoUTF16(TELEPHONY_CALL_STATE(mState)), + this); + if (NS_FAILED(res)) { + NS_WARNING("Failed to dispatch a specific event!"); + } + + return res; +} + nsresult TelephonyCall::DispatchCallEvent(const nsAString& aType, TelephonyCall* aCall) @@ -278,9 +308,10 @@ TelephonyCall::Answer(ErrorResult& aRv) return nullptr; } - if (mCallState != nsITelephonyService::CALL_STATE_INCOMING) { + if (mState != TelephonyCallState::Incoming) { NS_WARNING(nsPrintfCString("Answer on non-incoming call is rejected!" - " (State: %u)", mCallState).get()); + " (State: %s)", + TELEPHONY_CALL_STATE(mState)).get()); promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); return promise.forget(); } @@ -300,15 +331,16 @@ TelephonyCall::HangUp(ErrorResult& aRv) return nullptr; } - if (mCallState == nsITelephonyService::CALL_STATE_DISCONNECTED) { - NS_WARNING(nsPrintfCString("HangUp on previously disconnected call" - " is rejected! (State: %u)", mCallState).get()); + if (mState == TelephonyCallState::Disconnected) { + NS_WARNING(nsPrintfCString("HangUp on a disconnected call is rejected!" + " (State: %s)", + TELEPHONY_CALL_STATE(mState)).get()); promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); return promise.forget(); } nsCOMPtr callback = new TelephonyCallback(promise); - aRv = mCallState == nsITelephonyService::CALL_STATE_INCOMING ? + aRv = mState == TelephonyCallState::Incoming ? mTelephony->Service()->RejectCall(mServiceId, mCallIndex, callback) : mTelephony->Service()->HangUpCall(mServiceId, mCallIndex, callback); NS_ENSURE_TRUE(!aRv.Failed(), nullptr); @@ -334,30 +366,13 @@ TelephonyCall::Hold(ErrorResult& aRv) return promise.forget(); } -already_AddRefed -TelephonyCall::Resume(ErrorResult& aRv) -{ - nsRefPtr promise = CreatePromise(aRv); - if (!promise) { - return nullptr; - } - - nsCOMPtr callback = new TelephonyCallback(promise); - aRv = Resume(callback); - if (NS_WARN_IF(aRv.Failed() && - !aRv.ErrorCodeIs(NS_ERROR_DOM_INVALID_STATE_ERR))) { - return nullptr; - } - - return promise.forget(); -} - nsresult TelephonyCall::Hold(nsITelephonyCallback* aCallback) { - if (mCallState != nsITelephonyService::CALL_STATE_CONNECTED) { + if (mState != TelephonyCallState::Connected) { NS_WARNING(nsPrintfCString("Hold non-connected call is rejected!" - " (State: %u)", mCallState).get()); + " (State: %s)", + TELEPHONY_CALL_STATE(mState)).get()); aCallback->NotifyError(NS_LITERAL_STRING("InvalidStateError")); return NS_ERROR_DOM_INVALID_STATE_ERR; } @@ -389,11 +404,31 @@ TelephonyCall::Hold(nsITelephonyCallback* aCallback) return NS_OK; } +already_AddRefed +TelephonyCall::Resume(ErrorResult& aRv) +{ + nsRefPtr promise = CreatePromise(aRv); + if (!promise) { + return nullptr; + } + + nsCOMPtr callback = new TelephonyCallback(promise); + aRv = Resume(callback); + if (NS_WARN_IF(aRv.Failed() && + !aRv.ErrorCodeIs(NS_ERROR_DOM_INVALID_STATE_ERR))) { + return nullptr; + } + + return promise.forget(); +} + nsresult TelephonyCall::Resume(nsITelephonyCallback* aCallback) { - if (mCallState != nsITelephonyService::CALL_STATE_HELD) { - NS_WARNING("Resume non-held call is rejected!"); + if (mState != TelephonyCallState::Held) { + NS_WARNING(nsPrintfCString("Resume non-held call is rejected!" + " (State: %s)", + TELEPHONY_CALL_STATE(mState)).get()); aCallback->NotifyError(NS_LITERAL_STRING("InvalidStateError")); return NS_ERROR_DOM_INVALID_STATE_ERR; } diff --git a/dom/telephony/TelephonyCall.h b/dom/telephony/TelephonyCall.h index 0b31b447aa40..74dc6b1cd96e 100644 --- a/dom/telephony/TelephonyCall.h +++ b/dom/telephony/TelephonyCall.h @@ -29,7 +29,7 @@ class TelephonyCall final : public DOMEventTargetHelper nsRefPtr mSecondId; uint32_t mServiceId; - nsString mState; + TelephonyCallState mState; bool mEmergency; nsRefPtr mError; Nullable mDisconnectedReason; @@ -38,7 +38,6 @@ class TelephonyCall final : public DOMEventTargetHelper bool mMergeable; uint32_t mCallIndex; - uint16_t mCallState; bool mLive; public: @@ -65,10 +64,10 @@ public: already_AddRefed GetSecondId() const; - void - GetState(nsString& aState) const + TelephonyCallState + State() const { - aState.Assign(mState); + return mState; } bool @@ -89,6 +88,14 @@ public: return mMergeable; } + bool + IsActive() const + { + return mState == TelephonyCallState::Dialing || + mState == TelephonyCallState::Alerting || + mState == TelephonyCallState::Connected; + } + already_AddRefed GetError() const; @@ -122,18 +129,24 @@ public: IMPL_EVENT_HANDLER(error) IMPL_EVENT_HANDLER(groupchange) + static TelephonyCallState + ConvertToTelephonyCallState(uint32_t aCallState); + static already_AddRefed Create(Telephony* aTelephony, TelephonyCallId* aId, - uint32_t aServiceId, uint32_t aCallIndex, uint16_t aCallState, + uint32_t aServiceId, uint32_t aCallIndex, TelephonyCallState aState, bool aEmergency = false, bool aConference = false, bool aSwitchable = true, bool aMergeable = true); void - ChangeState(uint16_t aCallState) + ChangeState(TelephonyCallState aState) { - ChangeStateInternal(aCallState, true); + ChangeStateInternal(aState, true); } + nsresult + NotifyStateChanged(); + uint32_t ServiceId() const { @@ -146,12 +159,6 @@ public: return mCallIndex; } - uint16_t - CallState() const - { - return mCallState; - } - void UpdateEmergency(bool aEmergency) { @@ -194,7 +201,7 @@ private: Resume(nsITelephonyCallback* aCallback); void - ChangeStateInternal(uint16_t aCallState, bool aFireEvents); + ChangeStateInternal(TelephonyCallState aState, bool aFireEvents); nsresult DispatchCallEvent(const nsAString& aType, diff --git a/dom/telephony/TelephonyCallGroup.cpp b/dom/telephony/TelephonyCallGroup.cpp index 12040b6a31d7..15ff5ede25ac 100644 --- a/dom/telephony/TelephonyCallGroup.cpp +++ b/dom/telephony/TelephonyCallGroup.cpp @@ -10,16 +10,23 @@ #include "Telephony.h" #include "mozilla/dom/CallEvent.h" #include "mozilla/dom/CallGroupErrorEvent.h" -#include "mozilla/dom/TelephonyCallGroupBinding.h" #include "mozilla/dom/telephony/TelephonyCallback.h" +#include "nsPrintfCString.h" + +#ifdef TELEPHONY_GROUP_STATE +#undef TELEPHONY_GROUP_STATE +#endif + +#define TELEPHONY_GROUP_STATE(_state) \ + (TelephonyCallGroupStateValues::strings[static_cast(_state)].value) + using namespace mozilla::dom; using namespace mozilla::dom::telephony; using mozilla::ErrorResult; TelephonyCallGroup::TelephonyCallGroup(nsPIDOMWindow* aOwner) : DOMEventTargetHelper(aOwner) - , mCallState(nsITelephonyService::CALL_STATE_UNKNOWN) { } @@ -37,6 +44,7 @@ TelephonyCallGroup::Create(Telephony* aTelephony) new TelephonyCallGroup(aTelephony->GetOwner()); group->mTelephony = aTelephony; + group->mState = TelephonyCallGroupState::_empty; group->mCallsList = new CallsList(aTelephony, group); return group.forget(); @@ -82,48 +90,84 @@ TelephonyCallGroup::NotifyError(const nsAString& aName, const nsAString& aMessag } void -TelephonyCallGroup::ChangeState(uint16_t aCallState) +TelephonyCallGroup::ChangeState() { - if (mCallState == aCallState) { + MOZ_ASSERT(mCalls.Length() != 1); + if (mCalls.Length() == 0) { + ChangeStateInternal(TelephonyCallGroupState::_empty); return; } - mCallState = aCallState; - switch (aCallState) { - case nsITelephonyService::CALL_STATE_UNKNOWN: - mState.AssignLiteral(""); - break; - case nsITelephonyService::CALL_STATE_CONNECTED: - mState.AssignLiteral("connected"); - break; - case nsITelephonyService::CALL_STATE_HELD: - mState.AssignLiteral("held"); - break; - default: - NS_NOTREACHED("Unknown state!"); - } - - nsresult rv = DispatchCallEvent(NS_LITERAL_STRING("statechange"), nullptr); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to dispatch specific event!"); - } - if (!mState.IsEmpty()) { - // This can change if the statechange handler called back here... Need to - // figure out something smarter. - if (mCallState == aCallState) { - rv = DispatchCallEvent(mState, nullptr); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to dispatch specific event!"); - } + TelephonyCallState state = mCalls[0]->State(); + for (uint32_t i = 1; i < mCalls.Length(); i++) { + if (mCalls[i]->State() != state) { + MOZ_ASSERT(false, "Various call states are found in a call group!"); + ChangeStateInternal(TelephonyCallGroupState::_empty); + return; } } - for (uint32_t index = 0; index < mCalls.Length(); index++) { - nsRefPtr call = mCalls[index]; - call->ChangeState(aCallState); - - MOZ_ASSERT(call->CallState() == aCallState); + TelephonyCallGroupState groupState = TelephonyCallGroupState::_empty; + switch (state) { + case TelephonyCallState::Connected: + groupState = TelephonyCallGroupState::Connected; + break; + case TelephonyCallState::Held: + groupState = TelephonyCallGroupState::Held; + break; + default: + NS_NOTREACHED(nsPrintfCString("Invavild call state for a call group(%s)!", + TELEPHONY_CALL_STATE(state)).get()); } + + ChangeStateInternal(groupState); +} + +void +TelephonyCallGroup::ChangeStateInternal(TelephonyCallGroupState aState) +{ + if (mState == aState) { + return; + } + + // Update Current State + mState = aState; + + // Dispatch related events + NotifyStateChanged(); +} + +nsresult +TelephonyCallGroup::NotifyStateChanged() +{ + // Since |mState| can be changed after statechange handler called back here, + // we must save current state. Maybe we should figure out something smarter. + TelephonyCallGroupState prevState = mState; + + nsresult res = DispatchCallEvent(NS_LITERAL_STRING("statechange"), nullptr); + if (NS_FAILED(res)) { + NS_WARNING("Failed to dispatch specific event!"); + } + + // Check whether |mState| remains the same after the statechange handler. + // Besides, If there is no conference call at all, then we dont't have to + // dispatch the state evnet. + if (mState == prevState) { + res = DispatchCallEvent(NS_ConvertASCIItoUTF16(TELEPHONY_GROUP_STATE(mState)), + nullptr); + if (NS_FAILED(res)) { + NS_WARNING("Failed to dispatch specific event!"); + } + } + + // Notify each call within to dispatch call state change event + for (uint32_t index = 0; index < mCalls.Length(); index++) { + if (NS_FAILED(mCalls[index]->NotifyStateChanged())){ + res = NS_ERROR_FAILURE; + } + } + + return res; } nsresult @@ -172,14 +216,13 @@ TelephonyCallGroup::CanConference(const TelephonyCall& aCall, if (!aSecondCall) { MOZ_ASSERT(!mCalls.IsEmpty()); - - return (mCallState == nsITelephonyService::CALL_STATE_CONNECTED && - aCall.CallState() == nsITelephonyService::CALL_STATE_HELD) || - (mCallState == nsITelephonyService::CALL_STATE_HELD && - aCall.CallState() == nsITelephonyService::CALL_STATE_CONNECTED); + return (mState == TelephonyCallGroupState::Connected && + aCall.State() == TelephonyCallState::Held) || + (mState == TelephonyCallGroupState::Held && + aCall.State() == TelephonyCallState::Connected); } - MOZ_ASSERT(mCallState == nsITelephonyService::CALL_STATE_UNKNOWN); + MOZ_ASSERT(mState != TelephonyCallGroupState::_empty); if (aCall.ServiceId() != aSecondCall->ServiceId()) { return false; @@ -189,10 +232,10 @@ TelephonyCallGroup::CanConference(const TelephonyCall& aCall, return false; } - return (aCall.CallState() == nsITelephonyService::CALL_STATE_CONNECTED && - aSecondCall->CallState() == nsITelephonyService::CALL_STATE_HELD) || - (aCall.CallState() == nsITelephonyService::CALL_STATE_HELD && - aSecondCall->CallState() == nsITelephonyService::CALL_STATE_CONNECTED); + return (aCall.State() == TelephonyCallState::Connected && + aSecondCall->State() == TelephonyCallState::Held) || + (aCall.State() == TelephonyCallState::Held && + aSecondCall->State() == TelephonyCallState::Connected); } already_AddRefed @@ -297,7 +340,7 @@ TelephonyCallGroup::Remove(TelephonyCall& aCall, ErrorResult& aRv) return nullptr; } - if (mCallState != nsITelephonyService::CALL_STATE_CONNECTED) { + if (mState != TelephonyCallGroupState::Connected) { NS_WARNING("Remove call from a non-connected call group. Ignore!"); promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); return promise.forget(); @@ -330,6 +373,14 @@ TelephonyCallGroup::HangUp(ErrorResult& aRv) return nullptr; } + if (mState == TelephonyCallGroupState::_empty) { + NS_WARNING(nsPrintfCString("We don't have a call group now!" + " (State: %s)", + TELEPHONY_GROUP_STATE(mState)).get()); + promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); + return promise.forget(); + } + nsCOMPtr callback = new TelephonyCallback(promise); aRv = mTelephony->Service()->HangUpConference(mCalls[0]->ServiceId(), callback); @@ -357,6 +408,26 @@ TelephonyCallGroup::Hold(ErrorResult& aRv) return promise.forget(); } +nsresult +TelephonyCallGroup::Hold(nsITelephonyCallback* aCallback) +{ + if (mState != TelephonyCallGroupState::Connected) { + NS_WARNING(nsPrintfCString("Resume non-connected call group is rejected!" + " (State: %s)", + TELEPHONY_GROUP_STATE(mState)).get()); + aCallback->NotifyError(NS_LITERAL_STRING("InvalidStateError")); + return NS_ERROR_DOM_INVALID_STATE_ERR; + } + + nsresult rv = mTelephony->Service()->HoldConference(mCalls[0]->ServiceId(), + aCallback); + if (NS_WARN_IF(NS_FAILED(rv))) { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + already_AddRefed TelephonyCallGroup::Resume(ErrorResult& aRv) { @@ -377,29 +448,13 @@ TelephonyCallGroup::Resume(ErrorResult& aRv) return promise.forget(); } -nsresult -TelephonyCallGroup::Hold(nsITelephonyCallback* aCallback) -{ - if (mCallState != nsITelephonyService::CALL_STATE_CONNECTED) { - NS_WARNING("Holding a non-connected call is rejected!"); - aCallback->NotifyError(NS_LITERAL_STRING("InvalidStateError")); - return NS_ERROR_DOM_INVALID_STATE_ERR; - } - - nsresult rv = mTelephony->Service()->HoldConference(mCalls[0]->ServiceId(), - aCallback); - if (NS_WARN_IF(NS_FAILED(rv))) { - return NS_ERROR_FAILURE; - } - - return NS_OK; -} - nsresult TelephonyCallGroup::Resume(nsITelephonyCallback* aCallback) { - if (mCallState != nsITelephonyService::CALL_STATE_HELD) { - NS_WARNING("Resuming a non-held call is rejected!"); + if (mState != TelephonyCallGroupState::Held) { + NS_WARNING(nsPrintfCString("Resume non-held call group is rejected!" + " (State: %s)", + TELEPHONY_GROUP_STATE(mState)).get()); aCallback->NotifyError(NS_LITERAL_STRING("InvalidStateError")); return NS_ERROR_DOM_INVALID_STATE_ERR; } diff --git a/dom/telephony/TelephonyCallGroup.h b/dom/telephony/TelephonyCallGroup.h index 8e473b919951..a96bd1880055 100644 --- a/dom/telephony/TelephonyCallGroup.h +++ b/dom/telephony/TelephonyCallGroup.h @@ -8,6 +8,7 @@ #define mozilla_dom_telephony_telephonycallgroup_h__ #include "mozilla/dom/Promise.h" +#include "mozilla/dom/TelephonyCallGroupBinding.h" #include "mozilla/dom/telephony/TelephonyCommon.h" namespace mozilla { @@ -21,9 +22,7 @@ class TelephonyCallGroup final : public DOMEventTargetHelper nsRefPtr mCallsList; - nsString mState; - - uint16_t mCallState; + TelephonyCallGroupState mState; public: NS_DECL_ISUPPORTS_INHERITED @@ -64,10 +63,15 @@ public: already_AddRefed Resume(ErrorResult& aRv); - void - GetState(nsString& aState) const + TelephonyCallGroupState + State() const { - aState = mState; + return mState; + } + + bool + IsActive() { + return mState == TelephonyCallGroupState::Connected; } IMPL_EVENT_HANDLER(statechange) @@ -94,14 +98,9 @@ public: return mCalls; } + // Update its call state according to the calls wihtin itself. void - ChangeState(uint16_t aCallState); - - uint16_t - CallState() const - { - return mCallState; - } + ChangeState(); nsresult NotifyError(const nsAString& aName, const nsAString& aMessage); @@ -116,9 +115,15 @@ private: nsresult Resume(nsITelephonyCallback* aCallback); + nsresult + NotifyStateChanged(); + nsresult NotifyCallsChanged(TelephonyCall* aCall); + void + ChangeStateInternal(TelephonyCallGroupState aState); + nsresult DispatchCallEvent(const nsAString& aType, TelephonyCall* aCall); diff --git a/dom/telephony/TelephonyDialCallback.cpp b/dom/telephony/TelephonyDialCallback.cpp index 6ed78cce76fe..59d9cb4c7872 100644 --- a/dom/telephony/TelephonyDialCallback.cpp +++ b/dom/telephony/TelephonyDialCallback.cpp @@ -59,7 +59,7 @@ TelephonyDialCallback::NotifyDialCallSuccess(uint32_t aClientId, nsRefPtr id = mTelephony->CreateCallId(aNumber); nsRefPtr call = mTelephony->CreateCall(id, aClientId, aCallIndex, - nsITelephonyService::CALL_STATE_DIALING); + TelephonyCallState::Dialing); mPromise->MaybeResolve(call); return NS_OK; From 3023abe5bf3db98e8f55717b29a905941beaa3ff Mon Sep 17 00:00:00 2001 From: Tim Chien Date: Tue, 6 Oct 2015 07:44:00 +0200 Subject: [PATCH 043/228] Bug 1211387 - Remove background gradient of input boxes on UA style sheet, r=fabrice --- b2g/chrome/content/content.css | 22 ++++++------------- .../css-invalid/textarea/reftest.list | 4 ++-- .../css-ui-invalid/textarea/reftest.list | 4 ++-- .../css-ui-valid/textarea/reftest.list | 4 ++-- .../reftests/css-valid/textarea/reftest.list | 4 ++-- .../reftests/forms/input/range/reftest.list | 6 ++--- 6 files changed, 18 insertions(+), 26 deletions(-) diff --git a/b2g/chrome/content/content.css b/b2g/chrome/content/content.css index f8214856aa00..30ed355f047f 100644 --- a/b2g/chrome/content/content.css +++ b/b2g/chrome/content/content.css @@ -125,7 +125,7 @@ textarea, border-style: solid; border-color: #7d7d7d; color: #414141; - background: white linear-gradient(rgba(115,115,115,0.5) 0, rgba(215,215,215,0.5) 3px, rgba(255,255,255,0.2) 16px); + background-color: white; } /* Selects are handled by the form helper, see bug 685197 */ @@ -147,11 +147,11 @@ button { } input[type="checkbox"] { - background: white linear-gradient(rgba(115,115,115,0.5) 0, rgba(215,215,215,0.5) 2px, rgba(255,255,255,0.2) 6px); + background-color: white; } input[type="radio"] { - background: radial-gradient(at 6px 6px, rgba(255,255,255,0.2) 3px, rgba(195,195,195,0.5) 5px, rgba(115,115,115,0.5) 100%); + background-color: white; } select { @@ -226,7 +226,7 @@ input[type="file"]:focus > input[type="text"], outline: 0px !important; border-style: solid; border-color: rgb(94,128,153); - background: white linear-gradient(rgba(27,113,177,0.5) 0, rgba(198,225,246,0.2) 3px, rgba(255,255,255,0.2) 16px); + background-color: white; } select:not([size]):not([multiple]):focus, @@ -247,14 +247,6 @@ input[type="radio"]:focus { border-color: #99c6e0 !important; } -input[type="checkbox"]:focus { - background: white linear-gradient(rgba(27,113,177,0.5) 0, rgba(198,225,246,0.2) 2px, rgba(255,255,255,0.2) 6px); -} - -input[type="radio"]:focus { - background: radial-gradient(at 6px 6px, rgba(255,255,255,0.2) 3px, rgba(198,225,246,0.2) 5px, rgba(27,113,177,0.5) 100%); -} - /* we need to be specific for selects because the above rules are specific too */ textarea[disabled], select[size][disabled], @@ -269,13 +261,13 @@ button[disabled], border-color: rgba(125,125,125,0.4); border-style: solid; border-width: 1px; - background: transparent linear-gradient(rgba(185,185,185,0.4) 0, rgba(235,235,235,0.4) 3px, rgba(255,255,255,0.4) 100%); + background-color: #f5f5f5; } select:not([size]):not([multiple])[disabled], select[size="0"][disabled], select[size="1"][disabled] { - background: transparent linear-gradient(rgba(255,255,255,0.4) 0, rgba(235,235,235,0.4) 3px, rgba(185,185,185,0.4) 100%); + background-color: #f5f5f5; } input[type="button"][disabled], @@ -286,7 +278,7 @@ button[disabled] { -moz-padding-end: 7px; padding-block-start: 0; padding-block-end: 0; - background: transparent linear-gradient(rgba(255,255,255,0.4) 0, rgba(235,235,235,0.4) 3px, rgba(185,185,185,0.4) 100%); + background-color: #f5f5f5; } input[type="radio"][disabled], diff --git a/layout/reftests/css-invalid/textarea/reftest.list b/layout/reftests/css-invalid/textarea/reftest.list index 8fbedd96c771..329fb3b05264 100644 --- a/layout/reftests/css-invalid/textarea/reftest.list +++ b/layout/reftests/css-invalid/textarea/reftest.list @@ -1,7 +1,7 @@ == textarea-valid.html textarea-ref.html == textarea-customerror.html textarea-ref.html -fails-if(B2G||Mulet) == textarea-disabled.html textarea-ref.html # Initial mulet triage: parity with B2G/B2G Desktop -fails-if(B2G||Mulet) == textarea-dyn-disabled.html textarea-ref.html # Initial mulet triage: parity with B2G/B2G Desktop +== textarea-disabled.html textarea-ref.html +== textarea-dyn-disabled.html textarea-ref.html == textarea-dyn-not-disabled.html textarea-ref.html == textarea-readonly.html textarea-ref.html == textarea-dyn-readonly.html textarea-ref.html diff --git a/layout/reftests/css-ui-invalid/textarea/reftest.list b/layout/reftests/css-ui-invalid/textarea/reftest.list index 8f87e2245715..0e817dd6d2d2 100644 --- a/layout/reftests/css-ui-invalid/textarea/reftest.list +++ b/layout/reftests/css-ui-invalid/textarea/reftest.list @@ -1,7 +1,7 @@ == textarea-valid.html textarea-ref.html == textarea-customerror.html textarea-ref.html -skip-if(B2G||Mulet) == textarea-disabled.html textarea-ref.html # Initial mulet triage: parity with B2G/B2G Desktop -fails-if(B2G||Mulet) == textarea-dyn-disabled.html textarea-ref.html # Initial mulet triage: parity with B2G/B2G Desktop +== textarea-disabled.html textarea-ref.html +== textarea-dyn-disabled.html textarea-ref.html == textarea-dyn-not-disabled.html textarea-ref.html == textarea-readonly.html textarea-ref.html == textarea-dyn-readonly.html textarea-ref.html diff --git a/layout/reftests/css-ui-valid/textarea/reftest.list b/layout/reftests/css-ui-valid/textarea/reftest.list index 33df21f53633..b5907c27a569 100644 --- a/layout/reftests/css-ui-valid/textarea/reftest.list +++ b/layout/reftests/css-ui-valid/textarea/reftest.list @@ -1,7 +1,7 @@ == textarea-valid.html textarea-ref.html == textarea-customerror.html textarea-ref.html -fails-if(B2G||Mulet) == textarea-disabled.html textarea-ref.html # Initial mulet triage: parity with B2G/B2G Desktop -random-if(B2G||Mulet) == textarea-dyn-disabled.html textarea-ref.html # Initial mulet triage: parity with B2G/B2G Desktop +== textarea-disabled.html textarea-ref.html +== textarea-dyn-disabled.html textarea-ref.html == textarea-dyn-not-disabled.html textarea-ref.html == textarea-dyn-not-disabled-changed.html textarea-ref.html == textarea-readonly.html textarea-ref.html diff --git a/layout/reftests/css-valid/textarea/reftest.list b/layout/reftests/css-valid/textarea/reftest.list index 8fbedd96c771..329fb3b05264 100644 --- a/layout/reftests/css-valid/textarea/reftest.list +++ b/layout/reftests/css-valid/textarea/reftest.list @@ -1,7 +1,7 @@ == textarea-valid.html textarea-ref.html == textarea-customerror.html textarea-ref.html -fails-if(B2G||Mulet) == textarea-disabled.html textarea-ref.html # Initial mulet triage: parity with B2G/B2G Desktop -fails-if(B2G||Mulet) == textarea-dyn-disabled.html textarea-ref.html # Initial mulet triage: parity with B2G/B2G Desktop +== textarea-disabled.html textarea-ref.html +== textarea-dyn-disabled.html textarea-ref.html == textarea-dyn-not-disabled.html textarea-ref.html == textarea-readonly.html textarea-ref.html == textarea-dyn-readonly.html textarea-ref.html diff --git a/layout/reftests/forms/input/range/reftest.list b/layout/reftests/forms/input/range/reftest.list index dd516a6da8c3..5c5e09d88d1d 100644 --- a/layout/reftests/forms/input/range/reftest.list +++ b/layout/reftests/forms/input/range/reftest.list @@ -17,11 +17,11 @@ == value-prop.html 75pct-common-ref.html == valueAsNumber-prop-unthemed.html 75pct-unthemed-common-ref.html == valueAsNumber-prop.html 75pct-common-ref.html -fuzzy-if(B2G,1,1) == stepDown-unthemed.html 75pct-unthemed-common-ref.html -fuzzy-if(B2G,1,1) == stepDown.html 75pct-common-ref.html +fuzzy-if(B2G,2,1) == stepDown-unthemed.html 75pct-unthemed-common-ref.html +fuzzy-if(B2G,2,1) == stepDown.html 75pct-common-ref.html == stepUp-unthemed.html 75pct-unthemed-common-ref.html == stepUp.html 75pct-common-ref.html -fuzzy-if(B2G,1,1) == max-prop.html 100pct-common-ref.html +fuzzy-if(B2G,2,1) == max-prop.html 100pct-common-ref.html == reset-value.html reset-value-ref.html # 'direction' property: From 02f27f92183d4716182bbf40e43da4aa5ec69405 Mon Sep 17 00:00:00 2001 From: Yoshi Huang Date: Tue, 6 Oct 2015 15:36:10 +0800 Subject: [PATCH 044/228] Bug 1211636 - use ToInteger64 in PopulateFromSuffix. r=bholley From 76c9c3f887d6bce8b15abd37d5921887a187e18d Mon Sep 17 00:00:00 2001 --- caps/BasePrincipal.cpp | 16 ++++++------- caps/moz.build | 3 +++ caps/tests/gtest/TestOriginAttributes.cpp | 37 +++++++++++++++++++++++++++++++ caps/tests/gtest/moz.build | 13 +++++++++++ 4 files changed, 61 insertions(+), 8 deletions(-) create mode 100644 caps/tests/gtest/TestOriginAttributes.cpp create mode 100644 caps/tests/gtest/moz.build --- caps/BasePrincipal.cpp | 16 +++++----- caps/moz.build | 3 ++ caps/tests/gtest/TestOriginAttributes.cpp | 37 +++++++++++++++++++++++ caps/tests/gtest/moz.build | 13 ++++++++ 4 files changed, 61 insertions(+), 8 deletions(-) create mode 100644 caps/tests/gtest/TestOriginAttributes.cpp create mode 100644 caps/tests/gtest/moz.build diff --git a/caps/BasePrincipal.cpp b/caps/BasePrincipal.cpp index 2b026fe9b044..3623a102ca55 100644 --- a/caps/BasePrincipal.cpp +++ b/caps/BasePrincipal.cpp @@ -120,10 +120,10 @@ public: { if (aName.EqualsLiteral("appId")) { nsresult rv; - mOriginAttributes->mAppId = aValue.ToInteger(&rv); - if (NS_WARN_IF(NS_FAILED(rv))) { - return false; - } + int64_t val = aValue.ToInteger64(&rv); + NS_ENSURE_SUCCESS(rv, false); + NS_ENSURE_TRUE(val <= UINT32_MAX, false); + mOriginAttributes->mAppId = static_cast(val); return true; } @@ -145,10 +145,10 @@ public: if (aName.EqualsLiteral("userContextId")) { nsresult rv; - mOriginAttributes->mUserContextId = aValue.ToInteger(&rv); - if (NS_WARN_IF(NS_FAILED(rv))) { - return false; - } + int64_t val = aValue.ToInteger64(&rv); + NS_ENSURE_SUCCESS(rv, false); + NS_ENSURE_TRUE(val <= UINT32_MAX, false); + mOriginAttributes->mUserContextId = static_cast(val); return true; } diff --git a/caps/moz.build b/caps/moz.build index 2d8d46cef35b..365e8ddf8a6f 100644 --- a/caps/moz.build +++ b/caps/moz.build @@ -49,6 +49,9 @@ LOCAL_INCLUDES += [ '/js/xpconnect/src', ] +if CONFIG['ENABLE_TESTS']: + DIRS += ['tests/gtest'] + include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'xul' diff --git a/caps/tests/gtest/TestOriginAttributes.cpp b/caps/tests/gtest/TestOriginAttributes.cpp new file mode 100644 index 000000000000..c5f88fed40e8 --- /dev/null +++ b/caps/tests/gtest/TestOriginAttributes.cpp @@ -0,0 +1,37 @@ +/* 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 "gtest/gtest.h" +#include "mozilla/BasePrincipal.h" + +using mozilla::OriginAttributes; + +static void +TestSuffix(const OriginAttributes& attrs) +{ + nsAutoCString suffix; + attrs.CreateSuffix(suffix); + + OriginAttributes attrsFromSuffix; + attrsFromSuffix.PopulateFromSuffix(suffix); + + EXPECT_EQ(attrs, attrsFromSuffix); +} + +TEST(OriginAttributes, Suffix_default) +{ + OriginAttributes attrs; + TestSuffix(attrs); +} + +TEST(OriginAttributes, Suffix_appId_inBrowser) +{ + OriginAttributes attrs(1, true); + TestSuffix(attrs); +} + +TEST(OriginAttributes, Suffix_maxAppId_inBrowser) +{ + OriginAttributes attrs(4294967295, true); + TestSuffix(attrs); +} diff --git a/caps/tests/gtest/moz.build b/caps/tests/gtest/moz.build new file mode 100644 index 000000000000..5e1a6021202e --- /dev/null +++ b/caps/tests/gtest/moz.build @@ -0,0 +1,13 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +UNIFIED_SOURCES += [ + 'TestOriginAttributes.cpp' +] + +include('/ipc/chromium/chromium-config.mozbuild') + +FINAL_LIBRARY = 'xul-gtest' From 755316f7ffe9d9f7331caff562d2443beb3891f9 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Wed, 7 Oct 2015 01:25:20 -0700 Subject: [PATCH 045/228] Bumping gaia.json for 6 gaia revision(s) a=gaia-bump MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ======== https://hg.mozilla.org/integration/gaia-central/rev/d3bafd3af3d8 Author: Timothy Guan-tin Chien Desc: Merge pull request #32287 from mozilla-b2g/revert-31413-bug-1170236 Revert "Bug 1170236 - Get correct key management r=gasolin" ======== https://hg.mozilla.org/integration/gaia-central/rev/782ca093d907 Author: Timothy Guan-tin Chien Desc: Revert "Bug 1170236 - Get correct key management r=gasolin" ======== https://hg.mozilla.org/integration/gaia-central/rev/6b7d2372c6ed Author: Carsten Book Desc: Merge pull request #32277 from jedireza/private-browsing-setting-updates Bug 1211738 - [settings] private browsing setting string. r=tshakespeare ======== https://hg.mozilla.org/integration/gaia-central/rev/ea985fb8e5dd Author: jedireza Desc: Bug 1211738 - [settings] private browsing setting string ======== https://hg.mozilla.org/integration/gaia-central/rev/c96c843ebf73 Author: Carsten Book Desc: Merge pull request #32259 from mantaroh/master Bug 1205240 - [Simulator] Modify settings file in order to pass valid…. r=rchien ======== https://hg.mozilla.org/integration/gaia-central/rev/b7ec88c737f0 Author: mantaroh Desc: Bug 1205240 - [Simulator] Modify settings file in order to pass validation. r=seanlin --- b2g/config/gaia.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 0e218108c42c..20b6eb20804a 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,9 +1,9 @@ { "git": { - "git_revision": "77d463a009a1425e413edaae92b237e116708560", + "git_revision": "0e82f063dec7992dcd25ca4fe42f6b06513b46ad", "remote": "https://git.mozilla.org/releases/gaia.git", "branch": "" }, - "revision": "c00c454a571f087579b93184b878363351844ae2", + "revision": "d3bafd3af3d8f89c29efd1035aa8227b758cca27", "repo_path": "integration/gaia-central" } From 54a1fb5bb70dc4ba4eb85897470e2f9340e0f97f Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Wed, 7 Oct 2015 01:28:11 -0700 Subject: [PATCH 046/228] Bumping manifests a=b2g-bump --- b2g/config/aries/sources.xml | 2 +- b2g/config/dolphin/sources.xml | 2 +- b2g/config/emulator-ics/sources.xml | 2 +- b2g/config/emulator-jb/sources.xml | 2 +- b2g/config/emulator-kk/sources.xml | 2 +- b2g/config/emulator-l/sources.xml | 2 +- b2g/config/emulator/sources.xml | 2 +- b2g/config/flame-kk/sources.xml | 2 +- b2g/config/nexus-4-kk/sources.xml | 2 +- b2g/config/nexus-4/sources.xml | 2 +- b2g/config/nexus-5-l/sources.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/b2g/config/aries/sources.xml b/b2g/config/aries/sources.xml index eb2b43242e3d..7ce9111ea91d 100644 --- a/b2g/config/aries/sources.xml +++ b/b2g/config/aries/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index 24c1136ec358..ab8d2d25b756 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index 50ce079fc986..48de580198ae 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index 424d5301c5f9..6a68e9eb3177 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index df3d251f8378..133700420976 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-l/sources.xml b/b2g/config/emulator-l/sources.xml index 2481ad941309..88ea09eb5ff5 100644 --- a/b2g/config/emulator-l/sources.xml +++ b/b2g/config/emulator-l/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index 50ce079fc986..48de580198ae 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index ea4545a9cf16..392ed6cc4d2f 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/nexus-4-kk/sources.xml b/b2g/config/nexus-4-kk/sources.xml index 0ffa46db287c..106909287f7f 100644 --- a/b2g/config/nexus-4-kk/sources.xml +++ b/b2g/config/nexus-4-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index 170c924dc328..c3ae7a958012 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -18,7 +18,7 @@ - + diff --git a/b2g/config/nexus-5-l/sources.xml b/b2g/config/nexus-5-l/sources.xml index b5f3af4ecc23..ae1c702fe2dc 100644 --- a/b2g/config/nexus-5-l/sources.xml +++ b/b2g/config/nexus-5-l/sources.xml @@ -15,7 +15,7 @@ - + From 1fb1130a136bd95c8ed661033b9c24c846c96194 Mon Sep 17 00:00:00 2001 From: Mantaroh Yoshinaga Date: Mon, 5 Oct 2015 23:37:00 +0200 Subject: [PATCH 047/228] Bug 1205240 - Add JSON Validation code in order to prevent invalid file. r=seanlin --HG-- extra : rebase_source : a51099233f3a2d9d12773308804fa06917834bf7 --- dom/tv/TVSimulatorService.js | 106 +++++++++++++++++++++++++++++++++-- dom/tv/TVTuner.cpp | 2 +- 2 files changed, 102 insertions(+), 6 deletions(-) diff --git a/dom/tv/TVSimulatorService.js b/dom/tv/TVSimulatorService.js index a9fd2fe56f93..5efa87f4b6a2 100644 --- a/dom/tv/TVSimulatorService.js +++ b/dom/tv/TVSimulatorService.js @@ -4,7 +4,7 @@ "use strict"; function debug(aMsg) { - //dump("[TVSimulatorService] " + aMsg + "\n"); + //dump("[TVSimulatorService] " + aMsg + "\n"); } const Cc = Components.classes; @@ -14,6 +14,18 @@ const Cr = Components.returnCode; const TV_SIMULATOR_DUMMY_DIRECTORY = "dummy"; const TV_SIMULATOR_DUMMY_FILE = "settings.json"; +// See http://seanyhlin.github.io/TV-Manager-API/#idl-def-TVSourceType +const TV_SOURCE_TYPES = ["dvb-t","dvb-t2","dvb-c","dvb-c2","dvb-s", + "dvb-s2","dvb-h","dvb-sh","atsc","atsc-m/h", + "isdb-t","isdb-tb","isdb-s","isdb-c","1seg", + "dtmb","cmmb","t-dmb","s-dmb"]; +function containInvalidSourceType(aElement, aIndex, aArray) { + return !TV_SOURCE_TYPES.includes(aElement); +} + +// See http://seanyhlin.github.io/TV-Manager-API/#idl-def-TVChannelType +const TV_CHANNEL_TYPES = ["tv","radio","data"]; + Cu.import("resource://gre/modules/XPCOMUtils.jsm"); function TVSimulatorService() { @@ -66,7 +78,7 @@ TVSimulatorService.prototype = { cstream.close(); } - let settingObj; + let settingsObj; try { /* * @@ -109,18 +121,24 @@ TVSimulatorService.prototype = { * },] * } */ - settingObj = JSON.parse(settingStr); + settingsObj = JSON.parse(settingStr); } catch(e) { debug("File load error: " + e); return; } + // validation + if (!this._validateSettings(settingsObj)) { + debug("Failed to validate settings."); + return; + } + // Key is as follow // {'tunerId':tunerId, 'sourceType':sourceType} this._internalTuners = new Map(); // TVTunerData - for each (let tunerData in settingObj.tuners) { + for each (let tunerData in settingsObj.tuners) { let tuner = Cc["@mozilla.org/tv/tvtunerdata;1"] .createInstance(Ci.nsITVTunerData); tuner.id = tunerData.id; @@ -403,7 +421,7 @@ TVSimulatorService.prototype = { } let wrapChannelData = wrapTunerData.channels.get(aChannelNumber); - if (!wrapChannelData) { + if (!wrapChannelData || !wrapChannelData.videoFilePath) { return ""; } @@ -433,6 +451,84 @@ TVSimulatorService.prototype = { return dsFile.path; }, + + _validateSettings: function TVSimValidateSettings(aSettingsObject) { + return this._validateTuners(aSettingsObject.tuners); + }, + + _validateTuners: function TVSimValidateTuners(aTunersObject) { + let tunerIds = new Array(); + for each (let tuner in aTunersObject) { + if (!tuner.id || + !tuner.supportedType || + !tuner.supportedType.length || + tuner.supportedType.some(containInvalidSourceType) || + tunerIds.includes(tuner.id)) { + debug("invalid tuner data."); + return false; + } + tunerIds.push(tuner.id); + + if (!this._validateSources(tuner.sources)) { + return false; + } + } + return true; + }, + + _validateSources: function TVSimValidateSources(aSourcesObject) { + for each (let source in aSourcesObject) { + if (!source.type || + !TV_SOURCE_TYPES.includes(source.type)) { + debug("invalid source data."); + return false; + } + + if (!this._validateChannels(source.channels)) { + return false; + } + } + return true; + }, + + _validateChannels: function TVSimValidateChannels(aChannelsObject) { + let channelNumbers = new Array(); + for each (let channel in aChannelsObject) { + if (!channel.networkId || + !channel.transportStreamId || + !channel.serviceId || + !channel.type || + !TV_CHANNEL_TYPES.includes(channel.type) || + !channel.number || + channelNumbers.includes(channel.number) || + !channel.name) { + debug("invalid channel data."); + return false; + } + channelNumbers.push(channel.number); + + if (!this._validatePrograms(channel.programs)) { + return false; + } + } + return true; + }, + + _validatePrograms: function TVSimValidatePrograms(aProgramsObject) { + let eventIds = new Array(); + for each (let program in aProgramsObject) { + if (!program.eventId || + eventIds.includes(program.eventId) || + !program.title || + !program.startTime || + !program.duration) { + debug("invalid program data."); + return false; + } + eventIds.push(program.eventId); + } + return true; + }, }; this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TVSimulatorService]); diff --git a/dom/tv/TVTuner.cpp b/dom/tv/TVTuner.cpp index 51c0f2965ce7..3b57f15a6c98 100644 --- a/dom/tv/TVTuner.cpp +++ b/dom/tv/TVTuner.cpp @@ -285,7 +285,7 @@ TVTuner::CreateSimulatedMediaStream() currentChannelNumber, domWin, currentVideoBlobUrl); - if (NS_WARN_IF(NS_FAILED(rv))) { + if (NS_WARN_IF(NS_FAILED(rv) || currentVideoBlobUrl.IsEmpty())) { return nullptr; } From 274088e2b2807cf83f2342df490799d10e3dbda4 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Wed, 7 Oct 2015 02:10:20 -0700 Subject: [PATCH 048/228] Bumping gaia.json for 2 gaia revision(s) a=gaia-bump ======== https://hg.mozilla.org/integration/gaia-central/rev/cc1cc8813171 Author: lissyx Desc: Merge pull request #32272 from lissyx/bug1211972 Bug 1211972 - Use --trusted-host with PIP v7 and above r=aus ======== https://hg.mozilla.org/integration/gaia-central/rev/54abd850ee86 Author: Alexandre Lissy Desc: Bug 1211972 - Use --trusted-host with PIP v7 and above r=aus --- b2g/config/gaia.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 20b6eb20804a..af8eaccf84b1 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,9 +1,9 @@ { "git": { - "git_revision": "0e82f063dec7992dcd25ca4fe42f6b06513b46ad", + "git_revision": "d410fa1f06417a8e63ea4641210ccab9c6162910", "remote": "https://git.mozilla.org/releases/gaia.git", "branch": "" }, - "revision": "d3bafd3af3d8f89c29efd1035aa8227b758cca27", + "revision": "cc1cc8813171055525dc8f028f44f6c649fe088a", "repo_path": "integration/gaia-central" } From c0ec4d6cd22e8c3a584f2e864ae6bea7c50b2a65 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Wed, 7 Oct 2015 02:13:46 -0700 Subject: [PATCH 049/228] Bumping manifests a=b2g-bump --- b2g/config/aries/sources.xml | 2 +- b2g/config/dolphin/sources.xml | 2 +- b2g/config/emulator-ics/sources.xml | 2 +- b2g/config/emulator-jb/sources.xml | 2 +- b2g/config/emulator-kk/sources.xml | 2 +- b2g/config/emulator-l/sources.xml | 2 +- b2g/config/emulator/sources.xml | 2 +- b2g/config/flame-kk/sources.xml | 2 +- b2g/config/nexus-4-kk/sources.xml | 2 +- b2g/config/nexus-4/sources.xml | 2 +- b2g/config/nexus-5-l/sources.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/b2g/config/aries/sources.xml b/b2g/config/aries/sources.xml index 7ce9111ea91d..72595c22e2df 100644 --- a/b2g/config/aries/sources.xml +++ b/b2g/config/aries/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index ab8d2d25b756..678512638f27 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index 48de580198ae..579d5dc6f9d6 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index 6a68e9eb3177..a4951985c396 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index 133700420976..a5b9007452ba 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-l/sources.xml b/b2g/config/emulator-l/sources.xml index 88ea09eb5ff5..e88b9b255694 100644 --- a/b2g/config/emulator-l/sources.xml +++ b/b2g/config/emulator-l/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index 48de580198ae..579d5dc6f9d6 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index 392ed6cc4d2f..30cc733445f1 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/nexus-4-kk/sources.xml b/b2g/config/nexus-4-kk/sources.xml index 106909287f7f..f1b05d508d51 100644 --- a/b2g/config/nexus-4-kk/sources.xml +++ b/b2g/config/nexus-4-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index c3ae7a958012..57fd1c444aec 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -18,7 +18,7 @@ - + diff --git a/b2g/config/nexus-5-l/sources.xml b/b2g/config/nexus-5-l/sources.xml index ae1c702fe2dc..e761ac778c7c 100644 --- a/b2g/config/nexus-5-l/sources.xml +++ b/b2g/config/nexus-5-l/sources.xml @@ -15,7 +15,7 @@ - + From a0b730328018095fae4257fb130f65eef6f9e607 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Wed, 7 Oct 2015 02:40:23 -0700 Subject: [PATCH 050/228] Bumping gaia.json for 4 gaia revision(s) a=gaia-bump ======== https://hg.mozilla.org/integration/gaia-central/rev/0071e64ad134 Author: gasolin Desc: Merge pull request #32288 from gasolin/issue-1212235 Bug 1212235 - add usbHotProtocolSwitch config in default device-features.json, r=me ======== https://hg.mozilla.org/integration/gaia-central/rev/7d6026283a83 Author: gasolin Desc: Bug 1212235 - add usbHotProtocolSwitch config in default device-features.json, r=me ======== https://hg.mozilla.org/integration/gaia-central/rev/6105c53e4ed9 Author: Fischer-L Desc: Merge pull request #32190 from Fischer-L/ft-presentation-cast-video Bug 1210694 - [Stingray][fling-player][TV][2.5] Require control panel funcitons, r=evelynhung ======== https://hg.mozilla.org/integration/gaia-central/rev/34fea04f02df Author: Fischer.json Desc: Bug 1210694 - [Stingray][fling-player][TV][2.5] Require control panel functions --- b2g/config/gaia.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index af8eaccf84b1..08818cf05131 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,9 +1,9 @@ { "git": { - "git_revision": "d410fa1f06417a8e63ea4641210ccab9c6162910", + "git_revision": "44e807cf7218d4fd04310832b8def7ebbc4dcafd", "remote": "https://git.mozilla.org/releases/gaia.git", "branch": "" }, - "revision": "cc1cc8813171055525dc8f028f44f6c649fe088a", + "revision": "0071e64ad13401b56c5fee8b38ea2d8c15cae1db", "repo_path": "integration/gaia-central" } From 29861272f4c7383ae6dbb462bd373cea6efcf8ad Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Wed, 7 Oct 2015 02:43:46 -0700 Subject: [PATCH 051/228] Bumping manifests a=b2g-bump --- b2g/config/aries/sources.xml | 2 +- b2g/config/dolphin/sources.xml | 2 +- b2g/config/emulator-ics/sources.xml | 2 +- b2g/config/emulator-jb/sources.xml | 2 +- b2g/config/emulator-kk/sources.xml | 2 +- b2g/config/emulator-l/sources.xml | 2 +- b2g/config/emulator/sources.xml | 2 +- b2g/config/flame-kk/sources.xml | 2 +- b2g/config/nexus-4-kk/sources.xml | 2 +- b2g/config/nexus-4/sources.xml | 2 +- b2g/config/nexus-5-l/sources.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/b2g/config/aries/sources.xml b/b2g/config/aries/sources.xml index 72595c22e2df..dfcea1a243e9 100644 --- a/b2g/config/aries/sources.xml +++ b/b2g/config/aries/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index 678512638f27..cf1474580e44 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index 579d5dc6f9d6..67c39d77f269 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index a4951985c396..a45cf81f0320 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index a5b9007452ba..64ce33d453b6 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-l/sources.xml b/b2g/config/emulator-l/sources.xml index e88b9b255694..c2f2c83b7de0 100644 --- a/b2g/config/emulator-l/sources.xml +++ b/b2g/config/emulator-l/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index 579d5dc6f9d6..67c39d77f269 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index 30cc733445f1..7c05050d35b9 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/nexus-4-kk/sources.xml b/b2g/config/nexus-4-kk/sources.xml index f1b05d508d51..1a1debfd9f78 100644 --- a/b2g/config/nexus-4-kk/sources.xml +++ b/b2g/config/nexus-4-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index 57fd1c444aec..f6eb4f07c750 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -18,7 +18,7 @@ - + diff --git a/b2g/config/nexus-5-l/sources.xml b/b2g/config/nexus-5-l/sources.xml index e761ac778c7c..61db43dded79 100644 --- a/b2g/config/nexus-5-l/sources.xml +++ b/b2g/config/nexus-5-l/sources.xml @@ -15,7 +15,7 @@ - + From e5ebbda2b67208f84ce71ff8dc5b765e390f37a8 Mon Sep 17 00:00:00 2001 From: Benoit Chabod Date: Mon, 24 Aug 2015 01:29:00 +0800 Subject: [PATCH 052/228] Bug 1191205 - Cancel USSD sessions only when needed. r=edgar USSD sessions used to be cancelled everytime a new message was sent. The cancel logic has been moved, so that no cancel request is sent if the USSD code is coming from a reply to an existing session. --HG-- extra : rebase_source : a3d9cb271b0605471a9a8c889658ea00fe107ef3 --- dom/telephony/gonk/TelephonyService.js | 53 +++++++++++++------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/dom/telephony/gonk/TelephonyService.js b/dom/telephony/gonk/TelephonyService.js index 06c24f7174fa..c6136e186634 100644 --- a/dom/telephony/gonk/TelephonyService.js +++ b/dom/telephony/gonk/TelephonyService.js @@ -1064,14 +1064,22 @@ TelephonyService.prototype = { // Handle unknown MMI code as USSD. default: - this._sendUSSDInternal(aClientId, aMmi.fullMMI, aResponse => { - if (aResponse.errorMsg) { - aCallback.notifyDialMMIError(aResponse.errorMsg); - return; - } - - aCallback.notifyDialMMISuccess(""); - }); + if (this._ussdSessions[aClientId]) { + // Cancel the previous ussd session first. + this._cancelUSSDInternal(aClientId, aResponse => { + // Fail to cancel ussd session, report error instead of sending ussd + // request. + if (aResponse.errorMsg) { + aCallback.notifyDialMMIError(aResponse.errorMsg); + return; + } + this._sendUSSDInternal(aClientId, aMmi.fullMMI, + this._defaultMMICallbackHandler.bind(this, aCallback)); + }); + return; + } + this._sendUSSDInternal(aClientId, aMmi.fullMMI, + this._defaultMMICallbackHandler.bind(this, aCallback)); break; } }, @@ -1678,6 +1686,14 @@ TelephonyService.prototype = { } }, + _defaultMMICallbackHandler: function(aCallback, aResponse) { + if (aResponse.errorMsg) { + aCallback.notifyDialMMIError(aResponse.errorMsg); + } else { + aCallback.notifyDialMMISuccess(""); + } + }, + _getCallsWithState: function(aClientId, aState) { let calls = []; for (let i in this._currentCalls[aClientId]) { @@ -2132,24 +2148,9 @@ TelephonyService.prototype = { }, _sendUSSDInternal: function(aClientId, aUssd, aCallback) { - if (!this._ussdSessions[aClientId]) { - this._sendToRilWorker(aClientId, "sendUSSD", { ussd: aUssd }, aResponse => { - this._ussdSessions[aClientId] = !aResponse.errorMsg; - aCallback(aResponse); - }); - return; - } - - // Cancel the previous ussd session first. - this._cancelUSSDInternal(aClientId, aResponse => { - // Fail to cancel ussd session, report error instead of sending ussd - // request. - if (aResponse.errorMsg) { - aCallback(aResponse); - return; - } - - this._sendUSSDInternal(aClientId, aUssd, aCallback); + this._sendToRilWorker(aClientId, "sendUSSD", { ussd: aUssd }, aResponse => { + this._ussdSessions[aClientId] = !aResponse.errorMsg; + aCallback(aResponse); }); }, From 192d9479c1117114fd61f24d2886c9083b783364 Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Tue, 6 Oct 2015 00:15:02 -0700 Subject: [PATCH 053/228] Bug 977338 - Remove AtomicOperations-inl.h, r=lth --HG-- extra : commitid : DbOnIWRGaAp --- js/src/asmjs/AsmJSSignalHandlers.cpp | 2 - js/src/asmjs/AsmJSValidate.cpp | 1 - js/src/builtin/AtomicsObject.cpp | 1 - js/src/jit/AtomicOperations-inl.h | 41 ------------------- js/src/jit/AtomicOperations.h | 36 ++++++++++++++-- js/src/jit/BaselineIC.cpp | 1 - js/src/jit/CodeGenerator.cpp | 1 - js/src/jit/MIR.cpp | 2 - js/src/jit/RangeAnalysis.cpp | 2 - js/src/jit/arm/Assembler-arm.cpp | 1 + js/src/jit/arm/AtomicOperations-arm.h | 1 - js/src/jit/arm/disasm/Constants-arm.h | 5 +++ js/src/jit/arm/disasm/Disasm-arm.h | 5 +++ js/src/jit/arm64/AtomicOperations-arm64.h | 4 +- .../AtomicOperations-mips-shared.h | 3 +- js/src/jit/none/AtomicOperations-none.h | 2 +- .../x86-shared/AtomicOperations-x86-shared.h | 3 +- js/src/jsapi.cpp | 2 - js/src/jsarray.cpp | 2 - js/src/jsiter.cpp | 2 - js/src/jsobj.cpp | 2 - js/src/jsobjinlines.h | 1 - js/src/vm/Interpreter.cpp | 1 - js/src/vm/NativeObject.cpp | 1 - js/src/vm/SelfHosting.cpp | 2 - js/src/vm/SharedArrayObject.cpp | 2 - js/src/vm/SharedTypedArrayObject.cpp | 1 - js/src/vm/TypedArrayObject.cpp | 1 - 28 files changed, 52 insertions(+), 76 deletions(-) delete mode 100644 js/src/jit/AtomicOperations-inl.h diff --git a/js/src/asmjs/AsmJSSignalHandlers.cpp b/js/src/asmjs/AsmJSSignalHandlers.cpp index 4393e72013db..3685ece74afc 100644 --- a/js/src/asmjs/AsmJSSignalHandlers.cpp +++ b/js/src/asmjs/AsmJSSignalHandlers.cpp @@ -26,8 +26,6 @@ #include "jit/Disassembler.h" #include "vm/Runtime.h" -#include "jit/AtomicOperations-inl.h" - using namespace js; using namespace js::jit; diff --git a/js/src/asmjs/AsmJSValidate.cpp b/js/src/asmjs/AsmJSValidate.cpp index 55ffa08cbe20..4aa283321a30 100644 --- a/js/src/asmjs/AsmJSValidate.cpp +++ b/js/src/asmjs/AsmJSValidate.cpp @@ -51,7 +51,6 @@ #include "frontend/ParseNode-inl.h" #include "frontend/Parser-inl.h" -#include "jit/AtomicOperations-inl.h" #include "jit/MacroAssembler-inl.h" using namespace js; diff --git a/js/src/builtin/AtomicsObject.cpp b/js/src/builtin/AtomicsObject.cpp index 452bc8bd26e1..582dd80ff5df 100644 --- a/js/src/builtin/AtomicsObject.cpp +++ b/js/src/builtin/AtomicsObject.cpp @@ -63,7 +63,6 @@ #include "vm/TypedArrayObject.h" #include "jsobjinlines.h" -#include "jit/AtomicOperations-inl.h" using namespace js; diff --git a/js/src/jit/AtomicOperations-inl.h b/js/src/jit/AtomicOperations-inl.h deleted file mode 100644 index eb73e98579c3..000000000000 --- a/js/src/jit/AtomicOperations-inl.h +++ /dev/null @@ -1,41 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * 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/. */ - -#ifndef jit_AtomicOperations_inl_h -#define jit_AtomicOperations_inl_h - -#if defined(JS_CODEGEN_ARM) -# include "jit/arm/AtomicOperations-arm.h" -#elif defined(JS_CODEGEN_ARM64) -# include "jit/arm64/AtomicOperations-arm64.h" -#elif defined(JS_CODEGEN_MIPS32) -# include "jit/mips-shared/AtomicOperations-mips-shared.h" -#elif defined(JS_CODEGEN_NONE) -# include "jit/none/AtomicOperations-none.h" -#elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) -# include "jit/x86-shared/AtomicOperations-x86-shared.h" -#else -# error "Atomic operations must be defined for this platform" -#endif - -inline bool -js::jit::AtomicOperations::isLockfree(int32_t size) -{ - // Keep this in sync with visitAtomicIsLockFree() in jit/CodeGenerator.cpp. - - switch (size) { - case 1: - case 2: - case 4: - return true; - case 8: - return AtomicOperations::isLockfree8(); - default: - return false; - } -} - -#endif // jit_AtomicOperations_inl_h diff --git a/js/src/jit/AtomicOperations.h b/js/src/jit/AtomicOperations.h index 8cbd6d158d43..000310b1fa77 100644 --- a/js/src/jit/AtomicOperations.h +++ b/js/src/jit/AtomicOperations.h @@ -7,6 +7,8 @@ #ifndef jit_AtomicOperations_h #define jit_AtomicOperations_h +#include "mozilla/Types.h" + #include "vm/SharedMem.h" namespace js { @@ -55,9 +57,6 @@ class RegionLock; * a "relaxed atomic" access: it can read or write garbage if there's * a race. * - * To make use of the functions you generally have to include - * AtomicOperations-inl.h. - * * * Implementation notes. * @@ -275,7 +274,38 @@ class RegionLock uint32_t spinlock; }; +inline bool +AtomicOperations::isLockfree(int32_t size) +{ + // Keep this in sync with visitAtomicIsLockFree() in jit/CodeGenerator.cpp. + + switch (size) { + case 1: + case 2: + case 4: + return true; + case 8: + return AtomicOperations::isLockfree8(); + default: + return false; + } +} + } // namespace jit } // namespace js +#if defined(JS_CODEGEN_ARM) +# include "jit/arm/AtomicOperations-arm.h" +#elif defined(JS_CODEGEN_ARM64) +# include "jit/arm64/AtomicOperations-arm64.h" +#elif defined(JS_CODEGEN_MIPS32) +# include "jit/mips-shared/AtomicOperations-mips-shared.h" +#elif defined(JS_CODEGEN_NONE) +# include "jit/none/AtomicOperations-none.h" +#elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) +# include "jit/x86-shared/AtomicOperations-x86-shared.h" +#else +# error "Atomic operations must be defined for this platform" +#endif + #endif // jit_AtomicOperations_h diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 31526837828f..fd82702c09f9 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -33,7 +33,6 @@ #include "jsboolinlines.h" #include "jsscriptinlines.h" -#include "jit/AtomicOperations-inl.h" #include "jit/JitFrames-inl.h" #include "jit/MacroAssembler-inl.h" #include "jit/shared/Lowering-shared-inl.h" diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index befb0a9703a5..2e68247061b6 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -41,7 +41,6 @@ #include "jsboolinlines.h" -#include "jit/AtomicOperations-inl.h" #include "jit/MacroAssembler-inl.h" #include "jit/shared/CodeGenerator-shared-inl.h" #include "jit/shared/Lowering-shared-inl.h" diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 95142a8ea9e8..932f45dd18cb 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -28,8 +28,6 @@ #include "jsobjinlines.h" #include "jsscriptinlines.h" -#include "jit/AtomicOperations-inl.h" - using namespace js; using namespace js::jit; diff --git a/js/src/jit/RangeAnalysis.cpp b/js/src/jit/RangeAnalysis.cpp index 0a754d0b9fd2..66db6f78cc35 100644 --- a/js/src/jit/RangeAnalysis.cpp +++ b/js/src/jit/RangeAnalysis.cpp @@ -19,8 +19,6 @@ #include "jsopcodeinlines.h" -#include "jit/AtomicOperations-inl.h" - using namespace js; using namespace js::jit; diff --git a/js/src/jit/arm/Assembler-arm.cpp b/js/src/jit/arm/Assembler-arm.cpp index 8b4135898875..7a9e7241e4b9 100644 --- a/js/src/jit/arm/Assembler-arm.cpp +++ b/js/src/jit/arm/Assembler-arm.cpp @@ -20,6 +20,7 @@ #include "jit/arm/MacroAssembler-arm.h" #include "jit/ExecutableAllocator.h" #include "jit/JitCompartment.h" +#include "jit/MacroAssembler.h" using namespace js; using namespace js::jit; diff --git a/js/src/jit/arm/AtomicOperations-arm.h b/js/src/jit/arm/AtomicOperations-arm.h index 3efd86db28b4..54e442f4df89 100644 --- a/js/src/jit/arm/AtomicOperations-arm.h +++ b/js/src/jit/arm/AtomicOperations-arm.h @@ -10,7 +10,6 @@ #define jit_arm_AtomicOperations_arm_h #include "jit/arm/Architecture-arm.h" -#include "jit/AtomicOperations.h" #if defined(__clang__) || defined(__GNUC__) diff --git a/js/src/jit/arm/disasm/Constants-arm.h b/js/src/jit/arm/disasm/Constants-arm.h index 2e26309a36b0..de63f39dc329 100644 --- a/js/src/jit/arm/disasm/Constants-arm.h +++ b/js/src/jit/arm/disasm/Constants-arm.h @@ -10,6 +10,11 @@ #ifdef JS_DISASM_ARM +#include "mozilla/Assertions.h" +#include "mozilla/Types.h" + +#include + namespace js { namespace jit { namespace disasm { diff --git a/js/src/jit/arm/disasm/Disasm-arm.h b/js/src/jit/arm/disasm/Disasm-arm.h index 62e75e505792..5421a03c773d 100644 --- a/js/src/jit/arm/disasm/Disasm-arm.h +++ b/js/src/jit/arm/disasm/Disasm-arm.h @@ -10,6 +10,11 @@ #ifdef JS_DISASM_ARM +#include "mozilla/Assertions.h" +#include "mozilla/Types.h" + +#include + namespace js { namespace jit { namespace disasm { diff --git a/js/src/jit/arm64/AtomicOperations-arm64.h b/js/src/jit/arm64/AtomicOperations-arm64.h index 2706969a7bb2..0fb8ac690136 100644 --- a/js/src/jit/arm64/AtomicOperations-arm64.h +++ b/js/src/jit/arm64/AtomicOperations-arm64.h @@ -9,8 +9,10 @@ #ifndef jit_arm64_AtomicOperations_arm64_h #define jit_arm64_AtomicOperations_arm64_h +#include "mozilla/Assertions.h" +#include "mozilla/Types.h" + #include "jit/arm64/Architecture-arm64.h" -#include "jit/AtomicOperations.h" inline bool js::jit::AtomicOperations::isLockfree8() diff --git a/js/src/jit/mips-shared/AtomicOperations-mips-shared.h b/js/src/jit/mips-shared/AtomicOperations-mips-shared.h index 299817aff8e8..a9df01c88c67 100644 --- a/js/src/jit/mips-shared/AtomicOperations-mips-shared.h +++ b/js/src/jit/mips-shared/AtomicOperations-mips-shared.h @@ -9,7 +9,8 @@ #ifndef jit_mips_shared_AtomicOperations_mips_shared_h #define jit_mips_shared_AtomicOperations_mips_shared_h -#include "jit/AtomicOperations.h" +#include "mozilla/Assertions.h" +#include "mozilla/Types.h" #if defined(__clang__) || defined(__GNUC__) diff --git a/js/src/jit/none/AtomicOperations-none.h b/js/src/jit/none/AtomicOperations-none.h index ceceeed52abc..f08ccf9e0475 100644 --- a/js/src/jit/none/AtomicOperations-none.h +++ b/js/src/jit/none/AtomicOperations-none.h @@ -9,7 +9,7 @@ #ifndef jit_none_AtomicOperations_none_h #define jit_none_AtomicOperations_none_h -#include "jit/AtomicOperations.h" +#include "mozilla/Assertions.h" // A "none" build is never run (ref IRC discussion with h4writer) and // all functions here can therefore MOZ_CRASH, even if they are diff --git a/js/src/jit/x86-shared/AtomicOperations-x86-shared.h b/js/src/jit/x86-shared/AtomicOperations-x86-shared.h index beeecde6dca2..8631b6cbd5f0 100644 --- a/js/src/jit/x86-shared/AtomicOperations-x86-shared.h +++ b/js/src/jit/x86-shared/AtomicOperations-x86-shared.h @@ -9,7 +9,8 @@ #ifndef jit_shared_AtomicOperations_x86_shared_h #define jit_shared_AtomicOperations_x86_shared_h -#include "jit/AtomicOperations.h" +#include "mozilla/Assertions.h" +#include "mozilla/Types.h" // Lock-freedom on x86 and x64: // diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 77a15f5d431f..fb3fb14580fc 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -91,8 +91,6 @@ #include "jsfuninlines.h" #include "jsscriptinlines.h" -#include "jit/AtomicOperations-inl.h" - #include "vm/Interpreter-inl.h" #include "vm/NativeObject-inl.h" #include "vm/String-inl.h" diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 02a52bd5b43c..fa2b8233c70a 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -38,8 +38,6 @@ #include "jsatominlines.h" -#include "jit/AtomicOperations-inl.h" - #include "vm/ArgumentsObject-inl.h" #include "vm/ArrayObject-inl.h" #include "vm/Interpreter-inl.h" diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 8922f84484c4..328762d75e3a 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -35,8 +35,6 @@ #include "jsscriptinlines.h" -#include "jit/AtomicOperations-inl.h" - #include "vm/NativeObject-inl.h" #include "vm/Stack-inl.h" #include "vm/String-inl.h" diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index d8dcf40ed77a..28d440be96df 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -59,8 +59,6 @@ #include "jscntxtinlines.h" #include "jscompartmentinlines.h" -#include "jit/AtomicOperations-inl.h" - #include "vm/ArrayObject-inl.h" #include "vm/BooleanObject-inl.h" #include "vm/Interpreter-inl.h" diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 87a3d91edd08..9067a2bca019 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -29,7 +29,6 @@ #include "jscompartmentinlines.h" #include "jsgcinlines.h" -#include "jit/AtomicOperations-inl.h" #include "vm/TypeInference-inl.h" namespace js { diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 5a32a10e138d..a4a12f051325 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -48,7 +48,6 @@ #include "jsfuninlines.h" #include "jsscriptinlines.h" -#include "jit/AtomicOperations-inl.h" #include "jit/JitFrames-inl.h" #include "vm/Debugger-inl.h" #include "vm/NativeObject-inl.h" diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp index 051dd020fea6..06baa7e1c8e6 100644 --- a/js/src/vm/NativeObject.cpp +++ b/js/src/vm/NativeObject.cpp @@ -19,7 +19,6 @@ #include "jsobjinlines.h" #include "gc/Nursery-inl.h" -#include "jit/AtomicOperations-inl.h" #include "vm/ArrayObject-inl.h" #include "vm/ScopeObject-inl.h" #include "vm/Shape-inl.h" diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 147131081b5d..3b2a927d6683 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -40,8 +40,6 @@ #include "jsfuninlines.h" #include "jsscriptinlines.h" -#include "jit/AtomicOperations-inl.h" - #include "vm/BooleanObject-inl.h" #include "vm/NativeObject-inl.h" #include "vm/NumberObject-inl.h" diff --git a/js/src/vm/SharedArrayObject.cpp b/js/src/vm/SharedArrayObject.cpp index 1a7352e43e64..3c32bc11ffae 100644 --- a/js/src/vm/SharedArrayObject.cpp +++ b/js/src/vm/SharedArrayObject.cpp @@ -28,8 +28,6 @@ #include "jsobjinlines.h" -#include "jit/AtomicOperations-inl.h" - using namespace js; static inline void* diff --git a/js/src/vm/SharedTypedArrayObject.cpp b/js/src/vm/SharedTypedArrayObject.cpp index f16ae8926a6c..d8ca722541af 100644 --- a/js/src/vm/SharedTypedArrayObject.cpp +++ b/js/src/vm/SharedTypedArrayObject.cpp @@ -45,7 +45,6 @@ #include "jsatominlines.h" #include "jsobjinlines.h" -#include "jit/AtomicOperations-inl.h" #include "vm/Shape-inl.h" using namespace js; diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp index e92750b42eb6..9f6c375b2489 100644 --- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -40,7 +40,6 @@ #include "jsatominlines.h" -#include "jit/AtomicOperations-inl.h" #include "vm/NativeObject-inl.h" #include "vm/Shape-inl.h" From 6c3bc53e68452fe6ca26eb52336b3b2eefcac542 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Sun, 4 Oct 2015 22:17:20 -0600 Subject: [PATCH 054/228] Bug 1209464: Fix missing neutered window region in MessageChannel::WaitForInterruptNotify. Regression from bug 1189709; r=jimm --HG-- extra : rebase_source : 56caab29e3f48b6332f8cd1b47e1e830f75d9c74 extra : source : bed340eab428d1c0d86057771fb19b7090e0af51 --- ipc/glue/WindowsMessageLoop.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ipc/glue/WindowsMessageLoop.cpp b/ipc/glue/WindowsMessageLoop.cpp index c87133699796..27fd46d51f2c 100644 --- a/ipc/glue/WindowsMessageLoop.cpp +++ b/ipc/glue/WindowsMessageLoop.cpp @@ -1132,6 +1132,8 @@ MessageChannel::WaitForInterruptNotify() NS_ASSERTION(timerId, "SetTimer failed!"); } + NeuteredWindowRegion neuteredRgn(true); + MSG msg = { 0 }; // Don't get wrapped up in here if the child connection dies. From dcced52d74902bf1cce668699bdcefc9cd47abe8 Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Mon, 5 Oct 2015 09:31:36 -0400 Subject: [PATCH 055/228] bug 1176196 - update libjpeg-turbo to 1.4.2. r=jrmuizel --HG-- extra : commitid : E8TzkSU0TOC extra : rebase_source : df175815820cba7829062fd69f93f9a8aeceb473 --- media/libjpeg/MOZCHANGES | 27 ++---- media/libjpeg/README-turbo.txt | 34 +------ media/libjpeg/jccolor.c | 52 +++++++--- media/libjpeg/jcdctmgr.c | 18 +++- media/libjpeg/jchuff.c | 14 +-- media/libjpeg/jconfig.h | 7 ++ media/libjpeg/jdarith.c | 2 +- media/libjpeg/jdcolor.c | 54 ++++++++--- media/libjpeg/jddctmgr.c | 2 + media/libjpeg/jdhuff.c | 18 ++-- media/libjpeg/jdhuff.h | 6 +- media/libjpeg/jdphuff.c | 24 ++--- media/libjpeg/jfdctint.c | 8 +- media/libjpeg/jidctint.c | 123 ++++++++++++------------ media/libjpeg/jidctred.c | 18 ++-- media/libjpeg/jmorecfg.h | 7 +- media/libjpeg/jpegint.h | 16 ++- media/libjpeg/jversion.h | 6 +- media/libjpeg/mozilla.diff | 37 +++---- media/libjpeg/simd/jccolext-sse2-64.asm | 4 +- media/libjpeg/simd/jcgryext-sse2-64.asm | 4 +- media/libjpeg/simd/jcsample-sse2-64.asm | 12 +-- media/libjpeg/simd/jdcolext-sse2-64.asm | 4 +- media/libjpeg/simd/jdmrgext-sse2-64.asm | 8 +- media/libjpeg/simd/jdsample-sse2-64.asm | 8 +- media/libjpeg/simd/jidctflt-sse2-64.asm | 2 +- media/libjpeg/simd/jidctfst-sse2-64.asm | 4 +- media/libjpeg/simd/jidctint-sse2-64.asm | 2 +- media/libjpeg/simd/jidctred-sse2-64.asm | 4 +- media/libjpeg/simd/jquantf-sse2-64.asm | 2 +- media/libjpeg/simd/jquanti-sse2-64.asm | 2 +- media/libjpeg/simd/jsimd_mips.c | 4 + media/libjpeg/simd/jsimd_mips_dspr2.S | 13 +-- media/update-libjpeg.sh | 29 ++++++ 34 files changed, 341 insertions(+), 234 deletions(-) create mode 100755 media/update-libjpeg.sh diff --git a/media/libjpeg/MOZCHANGES b/media/libjpeg/MOZCHANGES index df1b28c68edd..cc7e09484c18 100644 --- a/media/libjpeg/MOZCHANGES +++ b/media/libjpeg/MOZCHANGES @@ -1,16 +1,12 @@ To upgrade to a new revision of libjpeg-turbo, do the following: -* Check out libjpeg-turbo from SVN: +* Check out libjpeg-turbo from git: - $ svn co https://libjpeg-turbo.svn.sourceforge.net/svnroot/libjpeg-turbo/trunk libjpeg-turbo + $ git clone https://github.com/libjpeg-turbo/libjpeg-turbo.git -* In a clean clone of mozilla-central, run the following commands +* In a clean clone of mozilla-central, run the update script (tag defaults to HEAD): - $ rm -rf media/libjpeg - $ svn export --ignore-externals /path/to/libjpeg-turbo media/libjpeg - $ cd media/libjpeg - -* Copy win/jsimdcfg.inc to simd/. + $ ./media/update-libjpeg.sh /path/to/libjpeg-turbo [tag] * Since libjpeg-turbo normally creates jconfig.h and jconfigint.h at build time and we use pre-generated versions, changes to jconfig.h.in and jconfigint.h.in @@ -41,23 +37,18 @@ To upgrade to a new revision of libjpeg-turbo, do the following: Of course, libjpeg-turbo might have added some new source files, so you'll have to look though and figure out which of these files to keep. -* Restore files modified in the Mozilla repository. - - $ hg revert --no-backup jconfig.h jconfigint.h Makefile.in MOZCHANGES \ - mozilla.diff simd/Makefile.in genTables.py - * Update jconfig.h and jconfigint.h as noted previously. -* Apply Mozilla-specific changes to upstream files. - - $ patch -p0 -i mozilla.diff - -* Update Makefile.in to build any new files. +* Update moz.build to build any new files. * Finally, tell hg that we've added or removed some files: $ hg addremove +== October 5, 2015 (libjpeg-turbo v1.4.2 d8da49effe6460d55239c4c009c57f42d8e4a494 2015-09-21) == + +* Updated to v1.4.2 release. + == January 15, 2015 (libjpeg-turbo v1.4.0 r1481 2015-01-07) == * Updated to v1.4.0 release. diff --git a/media/libjpeg/README-turbo.txt b/media/libjpeg/README-turbo.txt index f5cd613c7c77..28b6c4db35d6 100755 --- a/media/libjpeg/README-turbo.txt +++ b/media/libjpeg/README-turbo.txt @@ -28,33 +28,8 @@ broader range of users and developers. ** License ******************************************************************************* -Most of libjpeg-turbo inherits the non-restrictive, BSD-style license used by -libjpeg (see README.) The TurboJPEG wrapper (both C and Java versions) and -associated test programs bear a similar license, which is reproduced below: - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -- Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. -- Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. -- Neither the name of the libjpeg-turbo Project nor the names of its - contributors may be used to endorse or promote products derived from this - software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS", -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. +libjpeg-turbo is covered by three compatible BSD-style open source licenses. +Refer to LICENSE.txt for a roll-up of license terms. ******************************************************************************* @@ -311,8 +286,9 @@ following reasons: numbers on this, the typical difference in PNSR between the two algorithms is less than 0.10 dB, whereas changing the quality level by 1 in the upper range of the quality scale is typically more like a 1.0 dB difference.) --- When not using the SIMD extensions, then the accuracy of the floating point - DCT/IDCT can depend on the compiler and compiler settings. +-- If the floating point algorithms in libjpeg-turbo are not implemented using + SIMD instructions on a particular platform, then the accuracy of the + floating point DCT/IDCT can depend on the compiler settings. While libjpeg-turbo does emulate the libjpeg v8 API/ABI, under the hood, it is still using the same algorithms as libjpeg v6b, so there are several specific diff --git a/media/libjpeg/jccolor.c b/media/libjpeg/jccolor.c index 4be75f714412..34ea23b89f7b 100644 --- a/media/libjpeg/jccolor.c +++ b/media/libjpeg/jccolor.c @@ -5,7 +5,7 @@ * Copyright (C) 1991-1996, Thomas G. Lane. * libjpeg-turbo Modifications: * Copyright 2009 Pierre Ossman for Cendio AB - * Copyright (C) 2009-2012, D. R. Commander. + * Copyright (C) 2009-2012, 2015 D. R. Commander. * Copyright (C) 2014, MIPS Technologies, Inc., California * For conditions of distribution and use, see the accompanying README file. * @@ -464,24 +464,54 @@ null_convert (j_compress_ptr cinfo, JDIMENSION output_row, int num_rows) { register JSAMPROW inptr; - register JSAMPROW outptr; + register JSAMPROW outptr, outptr0, outptr1, outptr2, outptr3; register JDIMENSION col; register int ci; int nc = cinfo->num_components; JDIMENSION num_cols = cinfo->image_width; - while (--num_rows >= 0) { - /* It seems fastest to make a separate pass for each component. */ - for (ci = 0; ci < nc; ci++) { - inptr = *input_buf; - outptr = output_buf[ci][output_row]; + if (nc == 3) { + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr0 = output_buf[0][output_row]; + outptr1 = output_buf[1][output_row]; + outptr2 = output_buf[2][output_row]; + output_row++; for (col = 0; col < num_cols; col++) { - outptr[col] = inptr[ci]; /* don't need GETJSAMPLE() here */ - inptr += nc; + outptr0[col] = *inptr++; + outptr1[col] = *inptr++; + outptr2[col] = *inptr++; } } - input_buf++; - output_row++; + } else if (nc == 4) { + while (--num_rows >= 0) { + inptr = *input_buf++; + outptr0 = output_buf[0][output_row]; + outptr1 = output_buf[1][output_row]; + outptr2 = output_buf[2][output_row]; + outptr3 = output_buf[3][output_row]; + output_row++; + for (col = 0; col < num_cols; col++) { + outptr0[col] = *inptr++; + outptr1[col] = *inptr++; + outptr2[col] = *inptr++; + outptr3[col] = *inptr++; + } + } + } else { + while (--num_rows >= 0) { + /* It seems fastest to make a separate pass for each component. */ + for (ci = 0; ci < nc; ci++) { + inptr = *input_buf; + outptr = output_buf[ci][output_row]; + for (col = 0; col < num_cols; col++) { + outptr[col] = inptr[ci]; /* don't need GETJSAMPLE() here */ + inptr += nc; + } + } + input_buf++; + output_row++; + } } } diff --git a/media/libjpeg/jcdctmgr.c b/media/libjpeg/jcdctmgr.c index 7d4d3a067341..4cac66648398 100644 --- a/media/libjpeg/jcdctmgr.c +++ b/media/libjpeg/jcdctmgr.c @@ -6,7 +6,7 @@ * libjpeg-turbo Modifications: * Copyright (C) 1999-2006, MIYASAKA Masaru. * Copyright 2009 Pierre Ossman for Cendio AB - * Copyright (C) 2011, 2014 D. R. Commander + * Copyright (C) 2011, 2014-2015 D. R. Commander * For conditions of distribution and use, see the accompanying README file. * * This file contains the forward-DCT management logic. @@ -175,6 +175,19 @@ compute_reciprocal (UINT16 divisor, DCTELEM * dtbl) UDCTELEM c; int b, r; + if (divisor == 1) { + /* divisor == 1 means unquantized, so these reciprocal/correction/shift + * values will cause the C quantization algorithm to act like the + * identity function. Since only the C quantization algorithm is used in + * these cases, the scale value is irrelevant. + */ + dtbl[DCTSIZE2 * 0] = (DCTELEM) 1; /* reciprocal */ + dtbl[DCTSIZE2 * 1] = (DCTELEM) 0; /* correction */ + dtbl[DCTSIZE2 * 2] = (DCTELEM) 1; /* scale */ + dtbl[DCTSIZE2 * 3] = (DCTELEM) (-sizeof(DCTELEM) * 8); /* shift */ + return 0; + } + b = flss(divisor) - 1; r = sizeof(DCTELEM) * 8 + b; @@ -395,7 +408,8 @@ quantize (JCOEFPTR coef_block, DCTELEM * divisors, DCTELEM * workspace) #if BITS_IN_JSAMPLE == 8 - UDCTELEM recip, corr, shift; + UDCTELEM recip, corr; + int shift; UDCTELEM2 product; for (i = 0; i < DCTSIZE2; i++) { diff --git a/media/libjpeg/jchuff.c b/media/libjpeg/jchuff.c index a5c0a1fda336..4ecc18d61b88 100644 --- a/media/libjpeg/jchuff.c +++ b/media/libjpeg/jchuff.c @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1991-1997, Thomas G. Lane. * libjpeg-turbo Modifications: - * Copyright (C) 2009-2011, 2014 D. R. Commander. + * Copyright (C) 2009-2011, 2014-2015 D. R. Commander. * For conditions of distribution and use, see the accompanying README file. * * This file contains Huffman entropy encoding routines. @@ -376,7 +376,11 @@ dump_buffer (working_state * state) } \ } -#if __WORDSIZE==64 || defined(_WIN64) +#if !defined(_WIN32) && !defined(SIZEOF_SIZE_T) +#error Cannot determine word size +#endif + +#if SIZEOF_SIZE_T==8 || defined(_WIN64) #define EMIT_BITS(code, size) { \ CHECKBUF47() \ @@ -513,16 +517,14 @@ encode_one_block (working_state * state, JCOEFPTR block, int last_dc_val, /* Emit the Huffman-coded symbol for the number of bits */ code = dctbl->ehufco[nbits]; size = dctbl->ehufsi[nbits]; - PUT_BITS(code, size) - CHECKBUF15() + EMIT_BITS(code, size) /* Mask off any extra bits in code */ temp2 &= (((INT32) 1)< does not define. */ /* #undef size_t */ + +/* The size of `size_t', as computed by sizeof. */ +#ifdef HAVE_64BIT_BUILD +#define SIZEOF_SIZE_T 8 +#else +#define SIZEOF_SIZE_T 4 +#endif diff --git a/media/libjpeg/jdarith.c b/media/libjpeg/jdarith.c index c6a1a99ac846..885c8eb30f73 100644 --- a/media/libjpeg/jdarith.c +++ b/media/libjpeg/jdarith.c @@ -306,7 +306,7 @@ decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) } /* Scale and output the DC coefficient (assumes jpeg_natural_order[0]=0) */ - (*block)[0] = (JCOEF) (entropy->last_dc_val[ci] << cinfo->Al); + (*block)[0] = (JCOEF) LEFT_SHIFT(entropy->last_dc_val[ci], cinfo->Al); } return TRUE; diff --git a/media/libjpeg/jdcolor.c b/media/libjpeg/jdcolor.c index 779fa51ffc9c..38db90f26853 100644 --- a/media/libjpeg/jdcolor.c +++ b/media/libjpeg/jdcolor.c @@ -6,7 +6,7 @@ * Modified 2011 by Guido Vollbeding. * libjpeg-turbo Modifications: * Copyright 2009 Pierre Ossman for Cendio AB - * Copyright (C) 2009, 2011-2012, 2014, D. R. Commander. + * Copyright (C) 2009, 2011-2012, 2014-2015, D. R. Commander. * Copyright (C) 2013, Linaro Limited. * For conditions of distribution and use, see the accompanying README file. * @@ -364,23 +364,53 @@ null_convert (j_decompress_ptr cinfo, JSAMPIMAGE input_buf, JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows) { - register JSAMPROW inptr, outptr; - register JDIMENSION count; + register JSAMPROW inptr, inptr0, inptr1, inptr2, inptr3, outptr; + register JDIMENSION col; register int num_components = cinfo->num_components; JDIMENSION num_cols = cinfo->output_width; int ci; - while (--num_rows >= 0) { - for (ci = 0; ci < num_components; ci++) { - inptr = input_buf[ci][input_row]; - outptr = output_buf[0] + ci; - for (count = num_cols; count > 0; count--) { - *outptr = *inptr++; /* needn't bother with GETJSAMPLE() here */ - outptr += num_components; + if (num_components == 3) { + while (--num_rows >= 0) { + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + input_row++; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + *outptr++ = inptr0[col]; + *outptr++ = inptr1[col]; + *outptr++ = inptr2[col]; } } - input_row++; - output_buf++; + } else if (num_components == 4) { + while (--num_rows >= 0) { + inptr0 = input_buf[0][input_row]; + inptr1 = input_buf[1][input_row]; + inptr2 = input_buf[2][input_row]; + inptr3 = input_buf[3][input_row]; + input_row++; + outptr = *output_buf++; + for (col = 0; col < num_cols; col++) { + *outptr++ = inptr0[col]; + *outptr++ = inptr1[col]; + *outptr++ = inptr2[col]; + *outptr++ = inptr3[col]; + } + } + } else { + while (--num_rows >= 0) { + for (ci = 0; ci < num_components; ci++) { + inptr = input_buf[ci][input_row]; + outptr = *output_buf; + for (col = 0; col < num_cols; col++) { + outptr[ci] = inptr[col]; + outptr += num_components; + } + } + output_buf++; + input_row++; + } } } diff --git a/media/libjpeg/jddctmgr.c b/media/libjpeg/jddctmgr.c index 40e68f1f299f..6cc3310e3bd6 100644 --- a/media/libjpeg/jddctmgr.c +++ b/media/libjpeg/jddctmgr.c @@ -181,6 +181,7 @@ start_pass (j_decompress_ptr cinfo) break; } break; +#ifdef IDCT_SCALING_SUPPORTED case 9: method_ptr = jpeg_idct_9x9; method = JDCT_ISLOW; /* jidctint uses islow-style table */ @@ -218,6 +219,7 @@ start_pass (j_decompress_ptr cinfo) method_ptr = jpeg_idct_16x16; method = JDCT_ISLOW; /* jidctint uses islow-style table */ break; +#endif default: ERREXIT1(cinfo, JERR_BAD_DCTSIZE, compptr->_DCT_scaled_size); break; diff --git a/media/libjpeg/jdhuff.c b/media/libjpeg/jdhuff.c index 7dc132896965..aacc0366d7ee 100644 --- a/media/libjpeg/jdhuff.c +++ b/media/libjpeg/jdhuff.c @@ -91,6 +91,7 @@ start_pass_huff_decoder (j_decompress_ptr cinfo) { huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; int ci, blkn, dctbl, actbl; + d_derived_tbl **pdtbl; jpeg_component_info * compptr; /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG. @@ -107,10 +108,10 @@ start_pass_huff_decoder (j_decompress_ptr cinfo) actbl = compptr->ac_tbl_no; /* Compute derived values for Huffman tables */ /* We may do this more than once for a table, but it's not expensive */ - jpeg_make_d_derived_tbl(cinfo, TRUE, dctbl, - & entropy->dc_derived_tbls[dctbl]); - jpeg_make_d_derived_tbl(cinfo, FALSE, actbl, - & entropy->ac_derived_tbls[actbl]); + pdtbl = entropy->dc_derived_tbls + dctbl; + jpeg_make_d_derived_tbl(cinfo, TRUE, dctbl, pdtbl); + pdtbl = entropy->ac_derived_tbls + actbl; + jpeg_make_d_derived_tbl(cinfo, FALSE, actbl, pdtbl); /* Initialize DC predictions to 0 */ entropy->saved.last_dc_val[ci] = 0; } @@ -419,11 +420,11 @@ jpeg_fill_bit_buffer (bitread_working_state * state, } \ } -#if __WORDSIZE == 64 || defined(_WIN64) +#if SIZEOF_SIZE_T==8 || defined(_WIN64) /* Pre-fetch 48 bytes, because the holding register is 64-bit */ #define FILL_BIT_BUFFER_FAST \ - if (bits_left < 16) { \ + if (bits_left <= 16) { \ GET_BYTE GET_BYTE GET_BYTE GET_BYTE GET_BYTE GET_BYTE \ } @@ -431,7 +432,7 @@ jpeg_fill_bit_buffer (bitread_working_state * state, /* Pre-fetch 16 bytes, because the holding register is 32-bit */ #define FILL_BIT_BUFFER_FAST \ - if (bits_left < 16) { \ + if (bits_left <= 16) { \ GET_BYTE GET_BYTE \ } @@ -490,7 +491,8 @@ jpeg_huff_decode (bitread_working_state * state, #define AVOID_TABLES #ifdef AVOID_TABLES -#define HUFF_EXTEND(x,s) ((x) + ((((x) - (1<<((s)-1))) >> 31) & (((-1)<<(s)) + 1))) +#define NEG_1 ((unsigned int)-1) +#define HUFF_EXTEND(x,s) ((x) + ((((x) - (1<<((s)-1))) >> 31) & (((NEG_1)<<(s)) + 1))) #else diff --git a/media/libjpeg/jdhuff.h b/media/libjpeg/jdhuff.h index f2805e46cf71..c7f3d5008679 100644 --- a/media/libjpeg/jdhuff.h +++ b/media/libjpeg/jdhuff.h @@ -67,7 +67,11 @@ EXTERN(void) jpeg_make_d_derived_tbl * necessary. */ -#if __WORDSIZE == 64 || defined(_WIN64) +#if !defined(_WIN32) && !defined(SIZEOF_SIZE_T) +#error Cannot determine word size +#endif + +#if SIZEOF_SIZE_T==8 || defined(_WIN64) typedef size_t bit_buf_type; /* type of bit-extraction buffer */ #define BIT_BUF_SIZE 64 /* size of buffer in bits */ diff --git a/media/libjpeg/jdphuff.c b/media/libjpeg/jdphuff.c index eae1538360a2..7ef8e7b27a09 100644 --- a/media/libjpeg/jdphuff.c +++ b/media/libjpeg/jdphuff.c @@ -3,8 +3,8 @@ * * This file was part of the Independent JPEG Group's software: * Copyright (C) 1995-1997, Thomas G. Lane. - * It was modified by The libjpeg-turbo Project to include only code relevant - * to libjpeg-turbo. + * libjpeg-turbo Modifications: + * Copyright (C) 2015, D. R. Commander. * For conditions of distribution and use, see the accompanying README file. * * This file contains Huffman entropy decoding routines for progressive JPEG. @@ -96,6 +96,7 @@ start_pass_phuff_decoder (j_decompress_ptr cinfo) phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; boolean is_DC_band, bad; int ci, coefi, tbl; + d_derived_tbl **pdtbl; int *coef_bit_ptr; jpeg_component_info * compptr; @@ -168,13 +169,13 @@ start_pass_phuff_decoder (j_decompress_ptr cinfo) if (is_DC_band) { if (cinfo->Ah == 0) { /* DC refinement needs no table */ tbl = compptr->dc_tbl_no; - jpeg_make_d_derived_tbl(cinfo, TRUE, tbl, - & entropy->derived_tbls[tbl]); + pdtbl = entropy->derived_tbls + tbl; + jpeg_make_d_derived_tbl(cinfo, TRUE, tbl, pdtbl); } } else { tbl = compptr->ac_tbl_no; - jpeg_make_d_derived_tbl(cinfo, FALSE, tbl, - & entropy->derived_tbls[tbl]); + pdtbl = entropy->derived_tbls + tbl; + jpeg_make_d_derived_tbl(cinfo, FALSE, tbl, pdtbl); /* remember the single active table */ entropy->ac_derived_tbl = entropy->derived_tbls[tbl]; } @@ -203,7 +204,8 @@ start_pass_phuff_decoder (j_decompress_ptr cinfo) #define AVOID_TABLES #ifdef AVOID_TABLES -#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) + (((-1)<<(s)) + 1) : (x)) +#define NEG_1 ((unsigned)-1) +#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) + (((NEG_1)<<(s)) + 1) : (x)) #else @@ -336,7 +338,7 @@ decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) s += state.last_dc_val[ci]; state.last_dc_val[ci] = s; /* Scale and output the coefficient (assumes jpeg_natural_order[0]=0) */ - (*block)[0] = (JCOEF) (s << Al); + (*block)[0] = (JCOEF) LEFT_SHIFT(s, Al); } /* Completed MCU, so update state */ @@ -404,7 +406,7 @@ decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) r = GET_BITS(s); s = HUFF_EXTEND(r, s); /* Scale and output coefficient in natural (dezigzagged) order */ - (*block)[jpeg_natural_order[k]] = (JCOEF) (s << Al); + (*block)[jpeg_natural_order[k]] = (JCOEF) LEFT_SHIFT(s, Al); } else { if (r == 15) { /* ZRL */ k += 15; /* skip 15 zeroes in band */ @@ -495,8 +497,8 @@ decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) { phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy; int Se = cinfo->Se; - int p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ - int m1 = (-1) << cinfo->Al; /* -1 in the bit position being coded */ + int p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */ + int m1 = (NEG_1) << cinfo->Al; /* -1 in the bit position being coded */ register int s, k, r; unsigned int EOBRUN; JBLOCKROW block; diff --git a/media/libjpeg/jfdctint.c b/media/libjpeg/jfdctint.c index 14f486cdc7a7..68b083502275 100644 --- a/media/libjpeg/jfdctint.c +++ b/media/libjpeg/jfdctint.c @@ -1,8 +1,10 @@ /* * jfdctint.c * + * This file was part of the Independent JPEG Group's software. * Copyright (C) 1991-1996, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. + * libjpeg-turbo Modifications: + * Copyright (C) 2015, D. R. Commander * For conditions of distribution and use, see the accompanying README file. * * This file contains a slow-but-accurate integer implementation of the @@ -170,8 +172,8 @@ jpeg_fdct_islow (DCTELEM * data) tmp11 = tmp1 + tmp2; tmp12 = tmp1 - tmp2; - dataptr[0] = (DCTELEM) ((tmp10 + tmp11) << PASS1_BITS); - dataptr[4] = (DCTELEM) ((tmp10 - tmp11) << PASS1_BITS); + dataptr[0] = (DCTELEM) LEFT_SHIFT(tmp10 + tmp11, PASS1_BITS); + dataptr[4] = (DCTELEM) LEFT_SHIFT(tmp10 - tmp11, PASS1_BITS); z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100); dataptr[2] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp13, FIX_0_765366865), diff --git a/media/libjpeg/jidctint.c b/media/libjpeg/jidctint.c index 688fd2243c89..3429795c829b 100644 --- a/media/libjpeg/jidctint.c +++ b/media/libjpeg/jidctint.c @@ -1,9 +1,11 @@ /* * jidctint.c * + * This file was part of the Independent JPEG Group's software. * Copyright (C) 1991-1998, Thomas G. Lane. * Modification developed 2002-2009 by Guido Vollbeding. - * This file is part of the Independent JPEG Group's software. + * libjpeg-turbo Modifications: + * Copyright (C) 2015, D. R. Commander * For conditions of distribution and use, see the accompanying README file. * * This file contains a slow-but-accurate integer implementation of the @@ -205,7 +207,8 @@ jpeg_idct_islow (j_decompress_ptr cinfo, jpeg_component_info * compptr, inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && inptr[DCTSIZE*7] == 0) { /* AC terms all zero */ - int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; + int dcval = LEFT_SHIFT(DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]), + PASS1_BITS); wsptr[DCTSIZE*0] = dcval; wsptr[DCTSIZE*1] = dcval; @@ -235,8 +238,8 @@ jpeg_idct_islow (j_decompress_ptr cinfo, jpeg_component_info * compptr, z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); - tmp0 = (z2 + z3) << CONST_BITS; - tmp1 = (z2 - z3) << CONST_BITS; + tmp0 = LEFT_SHIFT(z2 + z3, CONST_BITS); + tmp1 = LEFT_SHIFT(z2 - z3, CONST_BITS); tmp10 = tmp0 + tmp3; tmp13 = tmp0 - tmp3; @@ -337,8 +340,8 @@ jpeg_idct_islow (j_decompress_ptr cinfo, jpeg_component_info * compptr, tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065); tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865); - tmp0 = ((INT32) wsptr[0] + (INT32) wsptr[4]) << CONST_BITS; - tmp1 = ((INT32) wsptr[0] - (INT32) wsptr[4]) << CONST_BITS; + tmp0 = LEFT_SHIFT((INT32) wsptr[0] + (INT32) wsptr[4], CONST_BITS); + tmp1 = LEFT_SHIFT((INT32) wsptr[0] - (INT32) wsptr[4], CONST_BITS); tmp10 = tmp0 + tmp3; tmp13 = tmp0 - tmp3; @@ -444,7 +447,7 @@ jpeg_idct_7x7 (j_decompress_ptr cinfo, jpeg_component_info * compptr, /* Even part */ tmp13 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp13 <<= CONST_BITS; + tmp13 = LEFT_SHIFT(tmp13, CONST_BITS); /* Add fudge factor here for final descale. */ tmp13 += ONE << (CONST_BITS-PASS1_BITS-1); @@ -499,7 +502,7 @@ jpeg_idct_7x7 (j_decompress_ptr cinfo, jpeg_component_info * compptr, /* Add fudge factor here for final descale. */ tmp13 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); - tmp13 <<= CONST_BITS; + tmp13 = LEFT_SHIFT(tmp13, CONST_BITS); z1 = (INT32) wsptr[2]; z2 = (INT32) wsptr[4]; @@ -593,7 +596,7 @@ jpeg_idct_6x6 (j_decompress_ptr cinfo, jpeg_component_info * compptr, /* Even part */ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp0 <<= CONST_BITS; + tmp0 = LEFT_SHIFT(tmp0, CONST_BITS); /* Add fudge factor here for final descale. */ tmp0 += ONE << (CONST_BITS-PASS1_BITS-1); tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); @@ -611,9 +614,9 @@ jpeg_idct_6x6 (j_decompress_ptr cinfo, jpeg_component_info * compptr, z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */ - tmp0 = tmp1 + ((z1 + z2) << CONST_BITS); - tmp2 = tmp1 + ((z3 - z2) << CONST_BITS); - tmp1 = (z1 - z2 - z3) << PASS1_BITS; + tmp0 = tmp1 + LEFT_SHIFT(z1 + z2, CONST_BITS); + tmp2 = tmp1 + LEFT_SHIFT(z3 - z2, CONST_BITS); + tmp1 = LEFT_SHIFT(z1 - z2 - z3, PASS1_BITS); /* Final output stage */ @@ -635,7 +638,7 @@ jpeg_idct_6x6 (j_decompress_ptr cinfo, jpeg_component_info * compptr, /* Add fudge factor here for final descale. */ tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); - tmp0 <<= CONST_BITS; + tmp0 = LEFT_SHIFT(tmp0, CONST_BITS); tmp2 = (INT32) wsptr[4]; tmp10 = MULTIPLY(tmp2, FIX(0.707106781)); /* c4 */ tmp1 = tmp0 + tmp10; @@ -651,9 +654,9 @@ jpeg_idct_6x6 (j_decompress_ptr cinfo, jpeg_component_info * compptr, z2 = (INT32) wsptr[3]; z3 = (INT32) wsptr[5]; tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */ - tmp0 = tmp1 + ((z1 + z2) << CONST_BITS); - tmp2 = tmp1 + ((z3 - z2) << CONST_BITS); - tmp1 = (z1 - z2 - z3) << CONST_BITS; + tmp0 = tmp1 + LEFT_SHIFT(z1 + z2, CONST_BITS); + tmp2 = tmp1 + LEFT_SHIFT(z3 - z2, CONST_BITS); + tmp1 = LEFT_SHIFT(z1 - z2 - z3, CONST_BITS); /* Final output stage */ @@ -714,7 +717,7 @@ jpeg_idct_5x5 (j_decompress_ptr cinfo, jpeg_component_info * compptr, /* Even part */ tmp12 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp12 <<= CONST_BITS; + tmp12 = LEFT_SHIFT(tmp12, CONST_BITS); /* Add fudge factor here for final descale. */ tmp12 += ONE << (CONST_BITS-PASS1_BITS-1); tmp0 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); @@ -724,7 +727,7 @@ jpeg_idct_5x5 (j_decompress_ptr cinfo, jpeg_component_info * compptr, z3 = tmp12 + z2; tmp10 = z3 + z1; tmp11 = z3 - z1; - tmp12 -= z2 << 2; + tmp12 -= LEFT_SHIFT(z2, 2); /* Odd part */ @@ -754,7 +757,7 @@ jpeg_idct_5x5 (j_decompress_ptr cinfo, jpeg_component_info * compptr, /* Add fudge factor here for final descale. */ tmp12 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); - tmp12 <<= CONST_BITS; + tmp12 = LEFT_SHIFT(tmp12, CONST_BITS); tmp0 = (INT32) wsptr[2]; tmp1 = (INT32) wsptr[4]; z1 = MULTIPLY(tmp0 + tmp1, FIX(0.790569415)); /* (c2+c4)/2 */ @@ -762,7 +765,7 @@ jpeg_idct_5x5 (j_decompress_ptr cinfo, jpeg_component_info * compptr, z3 = tmp12 + z2; tmp10 = z3 + z1; tmp11 = z3 - z1; - tmp12 -= z2 << 2; + tmp12 -= LEFT_SHIFT(z2, 2); /* Odd part */ @@ -828,7 +831,7 @@ jpeg_idct_3x3 (j_decompress_ptr cinfo, jpeg_component_info * compptr, /* Even part */ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp0 <<= CONST_BITS; + tmp0 = LEFT_SHIFT(tmp0, CONST_BITS); /* Add fudge factor here for final descale. */ tmp0 += ONE << (CONST_BITS-PASS1_BITS-1); tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); @@ -858,7 +861,7 @@ jpeg_idct_3x3 (j_decompress_ptr cinfo, jpeg_component_info * compptr, /* Add fudge factor here for final descale. */ tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); - tmp0 <<= CONST_BITS; + tmp0 = LEFT_SHIFT(tmp0, CONST_BITS); tmp2 = (INT32) wsptr[2]; tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */ tmp10 = tmp0 + tmp12; @@ -919,7 +922,7 @@ jpeg_idct_9x9 (j_decompress_ptr cinfo, jpeg_component_info * compptr, /* Even part */ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp0 <<= CONST_BITS; + tmp0 = LEFT_SHIFT(tmp0, CONST_BITS); /* Add fudge factor here for final descale. */ tmp0 += ONE << (CONST_BITS-PASS1_BITS-1); @@ -983,7 +986,7 @@ jpeg_idct_9x9 (j_decompress_ptr cinfo, jpeg_component_info * compptr, /* Add fudge factor here for final descale. */ tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); - tmp0 <<= CONST_BITS; + tmp0 = LEFT_SHIFT(tmp0, CONST_BITS); z1 = (INT32) wsptr[2]; z2 = (INT32) wsptr[4]; @@ -1091,7 +1094,7 @@ jpeg_idct_10x10 (j_decompress_ptr cinfo, jpeg_component_info * compptr, /* Even part */ z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - z3 <<= CONST_BITS; + z3 = LEFT_SHIFT(z3, CONST_BITS); /* Add fudge factor here for final descale. */ z3 += ONE << (CONST_BITS-PASS1_BITS-1); z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); @@ -1100,8 +1103,8 @@ jpeg_idct_10x10 (j_decompress_ptr cinfo, jpeg_component_info * compptr, tmp10 = z3 + z1; tmp11 = z3 - z2; - tmp22 = RIGHT_SHIFT(z3 - ((z1 - z2) << 1), /* c0 = (c4-c8)*2 */ - CONST_BITS-PASS1_BITS); + tmp22 = RIGHT_SHIFT(z3 - LEFT_SHIFT(z1 - z2, 1), + CONST_BITS-PASS1_BITS); /* c0 = (c4-c8)*2 */ z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); @@ -1126,7 +1129,7 @@ jpeg_idct_10x10 (j_decompress_ptr cinfo, jpeg_component_info * compptr, tmp13 = z2 - z4; tmp12 = MULTIPLY(tmp13, FIX(0.309016994)); /* (c3-c7)/2 */ - z5 = z3 << CONST_BITS; + z5 = LEFT_SHIFT(z3, CONST_BITS); z2 = MULTIPLY(tmp11, FIX(0.951056516)); /* (c3+c7)/2 */ z4 = z5 + tmp12; @@ -1135,9 +1138,9 @@ jpeg_idct_10x10 (j_decompress_ptr cinfo, jpeg_component_info * compptr, tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */ z2 = MULTIPLY(tmp11, FIX(0.587785252)); /* (c1-c9)/2 */ - z4 = z5 - tmp12 - (tmp13 << (CONST_BITS - 1)); + z4 = z5 - tmp12 - LEFT_SHIFT(tmp13, CONST_BITS - 1); - tmp12 = (z1 - tmp13 - z3) << PASS1_BITS; + tmp12 = LEFT_SHIFT(z1 - tmp13 - z3, PASS1_BITS); tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */ tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */ @@ -1166,14 +1169,14 @@ jpeg_idct_10x10 (j_decompress_ptr cinfo, jpeg_component_info * compptr, /* Add fudge factor here for final descale. */ z3 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); - z3 <<= CONST_BITS; + z3 = LEFT_SHIFT(z3, CONST_BITS); z4 = (INT32) wsptr[4]; z1 = MULTIPLY(z4, FIX(1.144122806)); /* c4 */ z2 = MULTIPLY(z4, FIX(0.437016024)); /* c8 */ tmp10 = z3 + z1; tmp11 = z3 - z2; - tmp22 = z3 - ((z1 - z2) << 1); /* c0 = (c4-c8)*2 */ + tmp22 = z3 - LEFT_SHIFT(z1 - z2, 1); /* c0 = (c4-c8)*2 */ z2 = (INT32) wsptr[2]; z3 = (INT32) wsptr[6]; @@ -1192,7 +1195,7 @@ jpeg_idct_10x10 (j_decompress_ptr cinfo, jpeg_component_info * compptr, z1 = (INT32) wsptr[1]; z2 = (INT32) wsptr[3]; z3 = (INT32) wsptr[5]; - z3 <<= CONST_BITS; + z3 = LEFT_SHIFT(z3, CONST_BITS); z4 = (INT32) wsptr[7]; tmp11 = z2 + z4; @@ -1207,9 +1210,9 @@ jpeg_idct_10x10 (j_decompress_ptr cinfo, jpeg_component_info * compptr, tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */ z2 = MULTIPLY(tmp11, FIX(0.587785252)); /* (c1-c9)/2 */ - z4 = z3 - tmp12 - (tmp13 << (CONST_BITS - 1)); + z4 = z3 - tmp12 - LEFT_SHIFT(tmp13, CONST_BITS - 1); - tmp12 = ((z1 - tmp13) << CONST_BITS) - z3; + tmp12 = LEFT_SHIFT(z1 - tmp13, CONST_BITS) - z3; tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */ tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */ @@ -1286,7 +1289,7 @@ jpeg_idct_11x11 (j_decompress_ptr cinfo, jpeg_component_info * compptr, /* Even part */ tmp10 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp10 <<= CONST_BITS; + tmp10 = LEFT_SHIFT(tmp10, CONST_BITS); /* Add fudge factor here for final descale. */ tmp10 += ONE << (CONST_BITS-PASS1_BITS-1); @@ -1359,7 +1362,7 @@ jpeg_idct_11x11 (j_decompress_ptr cinfo, jpeg_component_info * compptr, /* Add fudge factor here for final descale. */ tmp10 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); - tmp10 <<= CONST_BITS; + tmp10 = LEFT_SHIFT(tmp10, CONST_BITS); z1 = (INT32) wsptr[2]; z2 = (INT32) wsptr[4]; @@ -1480,7 +1483,7 @@ jpeg_idct_12x12 (j_decompress_ptr cinfo, jpeg_component_info * compptr, /* Even part */ z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - z3 <<= CONST_BITS; + z3 = LEFT_SHIFT(z3, CONST_BITS); /* Add fudge factor here for final descale. */ z3 += ONE << (CONST_BITS-PASS1_BITS-1); @@ -1492,9 +1495,9 @@ jpeg_idct_12x12 (j_decompress_ptr cinfo, jpeg_component_info * compptr, z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */ - z1 <<= CONST_BITS; + z1 = LEFT_SHIFT(z1, CONST_BITS); z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); - z2 <<= CONST_BITS; + z2 = LEFT_SHIFT(z2, CONST_BITS); tmp12 = z1 - z2; @@ -1563,7 +1566,7 @@ jpeg_idct_12x12 (j_decompress_ptr cinfo, jpeg_component_info * compptr, /* Add fudge factor here for final descale. */ z3 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); - z3 <<= CONST_BITS; + z3 = LEFT_SHIFT(z3, CONST_BITS); z4 = (INT32) wsptr[4]; z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */ @@ -1573,9 +1576,9 @@ jpeg_idct_12x12 (j_decompress_ptr cinfo, jpeg_component_info * compptr, z1 = (INT32) wsptr[2]; z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */ - z1 <<= CONST_BITS; + z1 = LEFT_SHIFT(z1, CONST_BITS); z2 = (INT32) wsptr[6]; - z2 <<= CONST_BITS; + z2 = LEFT_SHIFT(z2, CONST_BITS); tmp12 = z1 - z2; @@ -1696,7 +1699,7 @@ jpeg_idct_13x13 (j_decompress_ptr cinfo, jpeg_component_info * compptr, /* Even part */ z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - z1 <<= CONST_BITS; + z1 = LEFT_SHIFT(z1, CONST_BITS); /* Add fudge factor here for final descale. */ z1 += ONE << (CONST_BITS-PASS1_BITS-1); @@ -1784,7 +1787,7 @@ jpeg_idct_13x13 (j_decompress_ptr cinfo, jpeg_component_info * compptr, /* Add fudge factor here for final descale. */ z1 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); - z1 <<= CONST_BITS; + z1 = LEFT_SHIFT(z1, CONST_BITS); z2 = (INT32) wsptr[2]; z3 = (INT32) wsptr[4]; @@ -1924,7 +1927,7 @@ jpeg_idct_14x14 (j_decompress_ptr cinfo, jpeg_component_info * compptr, /* Even part */ z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - z1 <<= CONST_BITS; + z1 = LEFT_SHIFT(z1, CONST_BITS); /* Add fudge factor here for final descale. */ z1 += ONE << (CONST_BITS-PASS1_BITS-1); z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); @@ -1936,8 +1939,8 @@ jpeg_idct_14x14 (j_decompress_ptr cinfo, jpeg_component_info * compptr, tmp11 = z1 + z3; tmp12 = z1 - z4; - tmp23 = RIGHT_SHIFT(z1 - ((z2 + z3 - z4) << 1), /* c0 = (c4+c12-c8)*2 */ - CONST_BITS-PASS1_BITS); + tmp23 = RIGHT_SHIFT(z1 - LEFT_SHIFT(z2 + z3 - z4, 1), + CONST_BITS-PASS1_BITS); /* c0 = (c4+c12-c8)*2 */ z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); @@ -1962,7 +1965,7 @@ jpeg_idct_14x14 (j_decompress_ptr cinfo, jpeg_component_info * compptr, z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); - tmp13 = z4 << CONST_BITS; + tmp13 = LEFT_SHIFT(z4, CONST_BITS); tmp14 = z1 + z3; tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607)); /* c3 */ @@ -1981,7 +1984,7 @@ jpeg_idct_14x14 (j_decompress_ptr cinfo, jpeg_component_info * compptr, tmp14 += z4 + tmp13 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */ tmp15 += z4 + MULTIPLY(z2, FIX(0.674957567)); /* c1+c11-c5 */ - tmp13 = (z1 - z3) << PASS1_BITS; + tmp13 = LEFT_SHIFT(z1 - z3, PASS1_BITS); /* Final output stage */ @@ -2011,7 +2014,7 @@ jpeg_idct_14x14 (j_decompress_ptr cinfo, jpeg_component_info * compptr, /* Add fudge factor here for final descale. */ z1 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); - z1 <<= CONST_BITS; + z1 = LEFT_SHIFT(z1, CONST_BITS); z4 = (INT32) wsptr[4]; z2 = MULTIPLY(z4, FIX(1.274162392)); /* c4 */ z3 = MULTIPLY(z4, FIX(0.314692123)); /* c12 */ @@ -2021,7 +2024,7 @@ jpeg_idct_14x14 (j_decompress_ptr cinfo, jpeg_component_info * compptr, tmp11 = z1 + z3; tmp12 = z1 - z4; - tmp23 = z1 - ((z2 + z3 - z4) << 1); /* c0 = (c4+c12-c8)*2 */ + tmp23 = z1 - LEFT_SHIFT(z2 + z3 - z4, 1); /* c0 = (c4+c12-c8)*2 */ z1 = (INT32) wsptr[2]; z2 = (INT32) wsptr[6]; @@ -2046,7 +2049,7 @@ jpeg_idct_14x14 (j_decompress_ptr cinfo, jpeg_component_info * compptr, z2 = (INT32) wsptr[3]; z3 = (INT32) wsptr[5]; z4 = (INT32) wsptr[7]; - z4 <<= CONST_BITS; + z4 = LEFT_SHIFT(z4, CONST_BITS); tmp14 = z1 + z3; tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607)); /* c3 */ @@ -2064,7 +2067,7 @@ jpeg_idct_14x14 (j_decompress_ptr cinfo, jpeg_component_info * compptr, tmp14 += tmp13 + z4 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */ tmp15 += tmp13 + MULTIPLY(z2, FIX(0.674957567)); /* c1+c11-c5 */ - tmp13 = ((z1 - z3) << CONST_BITS) + z4; + tmp13 = LEFT_SHIFT(z1 - z3, CONST_BITS) + z4; /* Final output stage */ @@ -2150,7 +2153,7 @@ jpeg_idct_15x15 (j_decompress_ptr cinfo, jpeg_component_info * compptr, /* Even part */ z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - z1 <<= CONST_BITS; + z1 = LEFT_SHIFT(z1, CONST_BITS); /* Add fudge factor here for final descale. */ z1 += ONE << (CONST_BITS-PASS1_BITS-1); @@ -2163,7 +2166,7 @@ jpeg_idct_15x15 (j_decompress_ptr cinfo, jpeg_component_info * compptr, tmp12 = z1 - tmp10; tmp13 = z1 + tmp11; - z1 -= (tmp11 - tmp10) << 1; /* c0 = (c6-c12)*2 */ + z1 -= LEFT_SHIFT(tmp11 - tmp10, 1); /* c0 = (c6-c12)*2 */ z4 = z2 - z3; z3 += z2; @@ -2243,7 +2246,7 @@ jpeg_idct_15x15 (j_decompress_ptr cinfo, jpeg_component_info * compptr, /* Add fudge factor here for final descale. */ z1 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); - z1 <<= CONST_BITS; + z1 = LEFT_SHIFT(z1, CONST_BITS); z2 = (INT32) wsptr[2]; z3 = (INT32) wsptr[4]; @@ -2254,7 +2257,7 @@ jpeg_idct_15x15 (j_decompress_ptr cinfo, jpeg_component_info * compptr, tmp12 = z1 - tmp10; tmp13 = z1 + tmp11; - z1 -= (tmp11 - tmp10) << 1; /* c0 = (c6-c12)*2 */ + z1 -= LEFT_SHIFT(tmp11 - tmp10, 1); /* c0 = (c6-c12)*2 */ z4 = z2 - z3; z3 += z2; @@ -2392,7 +2395,7 @@ jpeg_idct_16x16 (j_decompress_ptr cinfo, jpeg_component_info * compptr, /* Even part */ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp0 <<= CONST_BITS; + tmp0 = LEFT_SHIFT(tmp0, CONST_BITS); /* Add fudge factor here for final descale. */ tmp0 += 1 << (CONST_BITS-PASS1_BITS-1); @@ -2494,7 +2497,7 @@ jpeg_idct_16x16 (j_decompress_ptr cinfo, jpeg_component_info * compptr, /* Add fudge factor here for final descale. */ tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2)); - tmp0 <<= CONST_BITS; + tmp0 = LEFT_SHIFT(tmp0, CONST_BITS); z1 = (INT32) wsptr[4]; tmp1 = MULTIPLY(z1, FIX(1.306562965)); /* c4[16] = c2[8] */ diff --git a/media/libjpeg/jidctred.c b/media/libjpeg/jidctred.c index 2b385f86cca0..4598698ffc3a 100644 --- a/media/libjpeg/jidctred.c +++ b/media/libjpeg/jidctred.c @@ -1,8 +1,10 @@ /* * jidctred.c * + * This file was part of the Independent JPEG Group's software. * Copyright (C) 1994-1998, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. + * libjpeg-turbo Modifications: + * Copyright (C) 2015, D. R. Commander * For conditions of distribution and use, see the accompanying README file. * * This file contains inverse-DCT routines that produce reduced-size output: @@ -143,7 +145,8 @@ jpeg_idct_4x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr, inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 && inptr[DCTSIZE*7] == 0) { /* AC terms all zero; we need not examine term 4 for 4x4 output */ - int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; + int dcval = LEFT_SHIFT(DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]), + PASS1_BITS); wsptr[DCTSIZE*0] = dcval; wsptr[DCTSIZE*1] = dcval; @@ -156,7 +159,7 @@ jpeg_idct_4x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr, /* Even part */ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp0 <<= (CONST_BITS+1); + tmp0 = LEFT_SHIFT(tmp0, CONST_BITS+1); z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); @@ -217,7 +220,7 @@ jpeg_idct_4x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr, /* Even part */ - tmp0 = ((INT32) wsptr[0]) << (CONST_BITS+1); + tmp0 = LEFT_SHIFT((INT32) wsptr[0], CONST_BITS+1); tmp2 = MULTIPLY((INT32) wsptr[2], FIX_1_847759065) + MULTIPLY((INT32) wsptr[6], - FIX_0_765366865); @@ -294,7 +297,8 @@ jpeg_idct_2x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr, if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*7] == 0) { /* AC terms all zero; we need not examine terms 2,4,6 for 2x2 output */ - int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS; + int dcval = LEFT_SHIFT(DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]), + PASS1_BITS); wsptr[DCTSIZE*0] = dcval; wsptr[DCTSIZE*1] = dcval; @@ -305,7 +309,7 @@ jpeg_idct_2x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr, /* Even part */ z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); - tmp10 = z1 << (CONST_BITS+2); + tmp10 = LEFT_SHIFT(z1, CONST_BITS+2); /* Odd part */ @@ -347,7 +351,7 @@ jpeg_idct_2x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr, /* Even part */ - tmp10 = ((INT32) wsptr[0]) << (CONST_BITS+2); + tmp10 = LEFT_SHIFT((INT32) wsptr[0], CONST_BITS+2); /* Odd part */ diff --git a/media/libjpeg/jmorecfg.h b/media/libjpeg/jmorecfg.h index 24d9d36c98e0..3b0d05af8941 100644 --- a/media/libjpeg/jmorecfg.h +++ b/media/libjpeg/jmorecfg.h @@ -3,8 +3,9 @@ * * This file was part of the Independent JPEG Group's software: * Copyright (C) 1991-1997, Thomas G. Lane. + * Modified 1997-2009 by Guido Vollbeding. * libjpeg-turbo Modifications: - * Copyright (C) 2009, 2011, 2014, D. R. Commander. + * Copyright (C) 2009, 2011, 2014-2015, D. R. Commander. * For conditions of distribution and use, see the accompanying README file. * * This file contains additional configuration options that customize the @@ -140,7 +141,9 @@ typedef int32_t INT32; * images up to 64K*64K due to 16-bit fields in SOF markers. Therefore * "unsigned int" is sufficient on all machines. However, if you need to * handle larger images and you don't mind deviating from the spec, you - * can change this datatype. + * can change this datatype. (Note that changing this datatype will + * potentially require modifying the SIMD code. The x86-64 SIMD extensions, + * in particular, assume a 32-bit JDIMENSION.) */ typedef unsigned int JDIMENSION; diff --git a/media/libjpeg/jpegint.h b/media/libjpeg/jpegint.h index 025accd91cf0..5f56b11064c1 100644 --- a/media/libjpeg/jpegint.h +++ b/media/libjpeg/jpegint.h @@ -4,8 +4,8 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1991-1997, Thomas G. Lane. * Modified 1997-2009 by Guido Vollbeding. - * It was modified by The libjpeg-turbo Project to include only code relevant - * to libjpeg-turbo. + * libjpeg-turbo Modifications: + * Copyright (C) 2015, D. R. Commander * For conditions of distribution and use, see the accompanying README file. * * This file provides common declarations for the various JPEG modules. @@ -42,6 +42,18 @@ typedef enum { /* Operating modes for buffer controllers */ #define DSTATE_STOPPING 210 /* looking for EOI in jpeg_finish_decompress */ +/* + * Left shift macro that handles a negative operand without causing any + * sanitizer warnings + */ + +#ifdef __INT32_IS_ACTUALLY_LONG +#define LEFT_SHIFT(a, b) ((INT32)((unsigned long)(a) << (b))) +#else +#define LEFT_SHIFT(a, b) ((INT32)((unsigned int)(a) << (b))) +#endif + + /* Declarations for compression modules */ /* Master control module */ diff --git a/media/libjpeg/jversion.h b/media/libjpeg/jversion.h index 25c3cf0b0c1d..949b4f4dcc44 100644 --- a/media/libjpeg/jversion.h +++ b/media/libjpeg/jversion.h @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1991-2012, Thomas G. Lane, Guido Vollbeding. * libjpeg-turbo Modifications: - * Copyright (C) 2010, 2012-2014, D. R. Commander. + * Copyright (C) 2010, 2012-2015, D. R. Commander. * For conditions of distribution and use, see the accompanying README file. * * This file contains software version identification. @@ -28,9 +28,9 @@ #define JCOPYRIGHT "Copyright (C) 1991-2012 Thomas G. Lane, Guido Vollbeding\n" \ "Copyright (C) 1999-2006 MIYASAKA Masaru\n" \ "Copyright (C) 2009 Pierre Ossman for Cendio AB\n" \ - "Copyright (C) 2009-2014 D. R. Commander\n" \ + "Copyright (C) 2009-2015 D. R. Commander\n" \ "Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies)\n" \ "Copyright (C) 2013-2014 MIPS Technologies, Inc.\n" \ "Copyright (C) 2013 Linaro Limited" -#define JCOPYRIGHT_SHORT "Copyright (C) 1991-2014 The libjpeg-turbo Project and many others" +#define JCOPYRIGHT_SHORT "Copyright (C) 1991-2015 The libjpeg-turbo Project and many others" diff --git a/media/libjpeg/mozilla.diff b/media/libjpeg/mozilla.diff index ea976a24e15a..207d863afef4 100644 --- a/media/libjpeg/mozilla.diff +++ b/media/libjpeg/mozilla.diff @@ -1,11 +1,8 @@ ---- jmorecfg.h 2014-11-25 05:07:43.000000000 -0500 -+++ jmorecfg.h 2015-01-14 21:46:56.465050782 -0500 -@@ -7,16 +7,17 @@ - * Copyright (C) 2009, 2011, 2014, D. R. Commander. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains additional configuration options that customize the - * JPEG software for special applications or support machine-dependent +diff --git jmorecfg.h jmorecfg.h +index be89189..3b0d05a 100644 +--- jmorecfg.h ++++ jmorecfg.h +@@ -13,6 +13,7 @@ * optimizations. Most users will not need to touch this file. */ @@ -13,17 +10,7 @@ /* * Maximum number of components (color channels) allowed in JPEG image. - * To meet the letter of the JPEG spec, set this to 255. However, darn - * few applications need more than 4 channels (maybe 5 for CMYK + alpha - * mask). We recommend 10 as a reasonable compromise; use 4 if you are - * really short on memory. (Each allowed component costs a hundred or so - * bytes of storage, whether actually used in an image or not.) -@@ -116,45 +117,29 @@ typedef char JOCTET; - * They must be at least as wide as specified; but making them too big - * won't cost a huge amount of memory, so we don't provide special - * extraction code like we did for JSAMPLE. (In other words, these - * typedefs live at a different point on the speed/space tradeoff curve.) - */ +@@ -122,42 +123,19 @@ typedef char JOCTET; /* UINT8 must hold at least the values 0..255. */ @@ -57,14 +44,16 @@ /* INT32 must hold at least signed 32-bit values. */ -#ifndef XMD_H /* X11/xmd.h correctly defines INT32 */ +-#ifndef _BASETSD_H_ /* Microsoft defines it in basetsd.h */ +-#ifndef _BASETSD_H /* MinGW is slightly different */ +-#ifndef QGLOBAL_H /* Qt defines it in qglobal.h */ +-#define __INT32_IS_ACTUALLY_LONG -typedef long INT32; -#endif +-#endif +-#endif +-#endif +typedef int32_t INT32; /* Datatype used for image dimensions. The JPEG standard only supports * images up to 64K*64K due to 16-bit fields in SOF markers. Therefore - * "unsigned int" is sufficient on all machines. However, if you need to - * handle larger images and you don't mind deviating from the spec, you - * can change this datatype. - */ - diff --git a/media/libjpeg/simd/jccolext-sse2-64.asm b/media/libjpeg/simd/jccolext-sse2-64.asm index 7bd6d016ec6e..7ad434381f94 100644 --- a/media/libjpeg/simd/jccolext-sse2-64.asm +++ b/media/libjpeg/simd/jccolext-sse2-64.asm @@ -50,14 +50,14 @@ EXTN(jsimd_rgb_ycc_convert_sse2): collect_args push rbx - mov rcx, r10 + mov ecx, r10d test rcx,rcx jz near .return push rcx mov rsi, r12 - mov rcx, r13 + mov ecx, r13d mov rdi, JSAMPARRAY [rsi+0*SIZEOF_JSAMPARRAY] mov rbx, JSAMPARRAY [rsi+1*SIZEOF_JSAMPARRAY] mov rdx, JSAMPARRAY [rsi+2*SIZEOF_JSAMPARRAY] diff --git a/media/libjpeg/simd/jcgryext-sse2-64.asm b/media/libjpeg/simd/jcgryext-sse2-64.asm index 5af02e04b1de..82c0fc812629 100644 --- a/media/libjpeg/simd/jcgryext-sse2-64.asm +++ b/media/libjpeg/simd/jcgryext-sse2-64.asm @@ -50,14 +50,14 @@ EXTN(jsimd_rgb_gray_convert_sse2): collect_args push rbx - mov rcx, r10 + mov ecx, r10d test rcx,rcx jz near .return push rcx mov rsi, r12 - mov rcx, r13 + mov ecx, r13d mov rdi, JSAMPARRAY [rsi+0*SIZEOF_JSAMPARRAY] lea rdi, [rdi+rcx*SIZEOF_JSAMPROW] diff --git a/media/libjpeg/simd/jcsample-sse2-64.asm b/media/libjpeg/simd/jcsample-sse2-64.asm index f32fb4fcc1a0..7693285c9008 100644 --- a/media/libjpeg/simd/jcsample-sse2-64.asm +++ b/media/libjpeg/simd/jcsample-sse2-64.asm @@ -49,11 +49,11 @@ EXTN(jsimd_h2v1_downsample_sse2): mov rbp,rsp collect_args - mov rcx, r13 + mov ecx, r13d shl rcx,3 ; imul rcx,DCTSIZE (rcx = output_cols) jz near .return - mov rdx, r10 + mov edx, r10d ; -- expand_right_edge @@ -90,7 +90,7 @@ EXTN(jsimd_h2v1_downsample_sse2): ; -- h2v1_downsample - mov rax, r12 ; rowctr + mov eax, r12d ; rowctr test eax,eax jle near .return @@ -193,11 +193,11 @@ EXTN(jsimd_h2v2_downsample_sse2): mov rbp,rsp collect_args - mov rcx, r13 + mov ecx, r13d shl rcx,3 ; imul rcx,DCTSIZE (rcx = output_cols) jz near .return - mov rdx, r10 + mov edx, r10d ; -- expand_right_edge @@ -234,7 +234,7 @@ EXTN(jsimd_h2v2_downsample_sse2): ; -- h2v2_downsample - mov rax, r12 ; rowctr + mov eax, r12d ; rowctr test rax,rax jle near .return diff --git a/media/libjpeg/simd/jdcolext-sse2-64.asm b/media/libjpeg/simd/jdcolext-sse2-64.asm index bfd1f35dff50..d356e6594a94 100644 --- a/media/libjpeg/simd/jdcolext-sse2-64.asm +++ b/media/libjpeg/simd/jdcolext-sse2-64.asm @@ -52,14 +52,14 @@ EXTN(jsimd_ycc_rgb_convert_sse2): collect_args push rbx - mov rcx, r10 ; num_cols + mov ecx, r10d ; num_cols test rcx,rcx jz near .return push rcx mov rdi, r11 - mov rcx, r12 + mov ecx, r12d mov rsi, JSAMPARRAY [rdi+0*SIZEOF_JSAMPARRAY] mov rbx, JSAMPARRAY [rdi+1*SIZEOF_JSAMPARRAY] mov rdx, JSAMPARRAY [rdi+2*SIZEOF_JSAMPARRAY] diff --git a/media/libjpeg/simd/jdmrgext-sse2-64.asm b/media/libjpeg/simd/jdmrgext-sse2-64.asm index ff127b573408..989d7f17c24e 100644 --- a/media/libjpeg/simd/jdmrgext-sse2-64.asm +++ b/media/libjpeg/simd/jdmrgext-sse2-64.asm @@ -52,14 +52,14 @@ EXTN(jsimd_h2v1_merged_upsample_sse2): collect_args push rbx - mov rcx, r10 ; col + mov ecx, r10d ; col test rcx,rcx jz near .return push rcx mov rdi, r11 - mov rcx, r12 + mov ecx, r12d mov rsi, JSAMPARRAY [rdi+0*SIZEOF_JSAMPARRAY] mov rbx, JSAMPARRAY [rdi+1*SIZEOF_JSAMPARRAY] mov rdx, JSAMPARRAY [rdi+2*SIZEOF_JSAMPARRAY] @@ -455,10 +455,10 @@ EXTN(jsimd_h2v2_merged_upsample_sse2): collect_args push rbx - mov rax, r10 + mov eax, r10d mov rdi, r11 - mov rcx, r12 + mov ecx, r12d mov rsi, JSAMPARRAY [rdi+0*SIZEOF_JSAMPARRAY] mov rbx, JSAMPARRAY [rdi+1*SIZEOF_JSAMPARRAY] mov rdx, JSAMPARRAY [rdi+2*SIZEOF_JSAMPARRAY] diff --git a/media/libjpeg/simd/jdsample-sse2-64.asm b/media/libjpeg/simd/jdsample-sse2-64.asm index 335ce2aabb3e..2287c00e5a27 100644 --- a/media/libjpeg/simd/jdsample-sse2-64.asm +++ b/media/libjpeg/simd/jdsample-sse2-64.asm @@ -67,7 +67,7 @@ EXTN(jsimd_h2v1_fancy_upsample_sse2): mov rbp,rsp collect_args - mov rax, r11 ; colctr + mov eax, r11d ; colctr test rax,rax jz near .return @@ -214,7 +214,7 @@ EXTN(jsimd_h2v2_fancy_upsample_sse2): collect_args push rbx - mov rax, r11 ; colctr + mov eax, r11d ; colctr test rax,rax jz near .return @@ -506,7 +506,7 @@ EXTN(jsimd_h2v1_upsample_sse2): mov rbp,rsp collect_args - mov rdx, r11 + mov edx, r11d add rdx, byte (2*SIZEOF_XMMWORD)-1 and rdx, byte -(2*SIZEOF_XMMWORD) jz near .return @@ -596,7 +596,7 @@ EXTN(jsimd_h2v2_upsample_sse2): collect_args push rbx - mov rdx, r11 + mov edx, r11d add rdx, byte (2*SIZEOF_XMMWORD)-1 and rdx, byte -(2*SIZEOF_XMMWORD) jz near .return diff --git a/media/libjpeg/simd/jidctflt-sse2-64.asm b/media/libjpeg/simd/jidctflt-sse2-64.asm index 32e4ec222cfe..95bd4dcd1716 100644 --- a/media/libjpeg/simd/jidctflt-sse2-64.asm +++ b/media/libjpeg/simd/jidctflt-sse2-64.asm @@ -326,7 +326,7 @@ EXTN(jsimd_idct_float_sse2): mov rax, [original_rbp] lea rsi, [workspace] ; FAST_FLOAT * wsptr mov rdi, r12 ; (JSAMPROW *) - mov rax, r13 + mov eax, r13d mov rcx, DCTSIZE/4 ; ctr .rowloop: diff --git a/media/libjpeg/simd/jidctfst-sse2-64.asm b/media/libjpeg/simd/jidctfst-sse2-64.asm index 85669527c4d8..0f864291e942 100644 --- a/media/libjpeg/simd/jidctfst-sse2-64.asm +++ b/media/libjpeg/simd/jidctfst-sse2-64.asm @@ -13,7 +13,7 @@ ; can *not* be assembled with Microsoft's MASM or any compatible ; assembler (including Borland's Turbo Assembler). ; NASM is available from http://nasm.sourceforge.net/ or -; http://sourceforge.net/projecpt/showfiles.php?group_id=6208 +; http://sourceforge.net/project/showfiles.php?group_id=6208 ; ; This file contains a fast, not so accurate integer implementation of ; the inverse DCT (Discrete Cosine Transform). The following code is @@ -323,7 +323,7 @@ EXTN(jsimd_idct_ifast_sse2): mov rax, [original_rbp] mov rdi, r12 ; (JSAMPROW *) - mov rax, r13 + mov eax, r13d ; -- Even part diff --git a/media/libjpeg/simd/jidctint-sse2-64.asm b/media/libjpeg/simd/jidctint-sse2-64.asm index 32bbfd8d3a6d..1cc308660010 100644 --- a/media/libjpeg/simd/jidctint-sse2-64.asm +++ b/media/libjpeg/simd/jidctint-sse2-64.asm @@ -515,7 +515,7 @@ EXTN(jsimd_idct_islow_sse2): mov rax, [original_rbp] mov rdi, r12 ; (JSAMPROW *) - mov rax, r13 + mov eax, r13d ; -- Even part diff --git a/media/libjpeg/simd/jidctred-sse2-64.asm b/media/libjpeg/simd/jidctred-sse2-64.asm index dad43d9056fc..02b155a801b1 100644 --- a/media/libjpeg/simd/jidctred-sse2-64.asm +++ b/media/libjpeg/simd/jidctred-sse2-64.asm @@ -312,7 +312,7 @@ EXTN(jsimd_idct_4x4_sse2): mov rax, [original_rbp] mov rdi, r12 ; (JSAMPROW *) - mov rax, r13 + mov eax, r13d ; -- Even part @@ -521,7 +521,7 @@ EXTN(jsimd_idct_2x2_sse2): ; ---- Pass 2: process rows, store into output array. mov rdi, r12 ; (JSAMPROW *) - mov rax, r13 + mov eax, r13d ; | input:| result:| ; | A0 B0 | | diff --git a/media/libjpeg/simd/jquantf-sse2-64.asm b/media/libjpeg/simd/jquantf-sse2-64.asm index 20e815f7d145..cf7f0d82782b 100644 --- a/media/libjpeg/simd/jquantf-sse2-64.asm +++ b/media/libjpeg/simd/jquantf-sse2-64.asm @@ -50,7 +50,7 @@ EXTN(jsimd_convsamp_float_sse2): packsswb xmm7,xmm7 ; xmm7 = PB_CENTERJSAMPLE (0x808080..) mov rsi, r10 - mov rax, r11 + mov eax, r11d mov rdi, r12 mov rcx, DCTSIZE/2 .convloop: diff --git a/media/libjpeg/simd/jquanti-sse2-64.asm b/media/libjpeg/simd/jquanti-sse2-64.asm index 50b8dce7a26d..b61f4db29e98 100644 --- a/media/libjpeg/simd/jquanti-sse2-64.asm +++ b/media/libjpeg/simd/jquanti-sse2-64.asm @@ -50,7 +50,7 @@ EXTN(jsimd_convsamp_sse2): psllw xmm7,7 ; xmm7={0xFF80 0xFF80 0xFF80 0xFF80 ..} mov rsi, r10 - mov rax, r11 + mov eax, r11d mov rdi, r12 mov rcx, DCTSIZE/4 .convloop: diff --git a/media/libjpeg/simd/jsimd_mips.c b/media/libjpeg/simd/jsimd_mips.c index abcd19f549dc..cf87b32bd948 100644 --- a/media/libjpeg/simd/jsimd_mips.c +++ b/media/libjpeg/simd/jsimd_mips.c @@ -562,6 +562,8 @@ jsimd_h2v1_fancy_upsample (j_decompress_ptr cinfo, GLOBAL(int) jsimd_can_h2v2_merged_upsample (void) { + init_simd(); + if (BITS_IN_JSAMPLE != 8) return 0; if (sizeof(JDIMENSION) != 4) @@ -576,6 +578,8 @@ jsimd_can_h2v2_merged_upsample (void) GLOBAL(int) jsimd_can_h2v1_merged_upsample (void) { + init_simd(); + if (BITS_IN_JSAMPLE != 8) return 0; if (sizeof(JDIMENSION) != 4) diff --git a/media/libjpeg/simd/jsimd_mips_dspr2.S b/media/libjpeg/simd/jsimd_mips_dspr2.S index 4572a51fa539..65c169abd826 100644 --- a/media/libjpeg/simd/jsimd_mips_dspr2.S +++ b/media/libjpeg/simd/jsimd_mips_dspr2.S @@ -916,7 +916,8 @@ LEAF_MIPS_DSPR2(jsimd_h2v2_fancy_upsample_mips_dspr2) srl t1, t1, 4 sb t0, 0(s3) sb t1, 1(s3) - addiu s3, 2 + beq t8, s0, 22f // skip to final iteration if width == 3 + addiu s3, 2 2: lh t0, 0(s0) // t0 = A3|A2 lh t2, 0(s1) // t2 = B3|B2 @@ -949,6 +950,7 @@ LEAF_MIPS_DSPR2(jsimd_h2v2_fancy_upsample_mips_dspr2) sb t2, 3(s3) bne t8, s0, 2b addiu s3, 4 +22: beqz s5, 4f addu t8, s0, s5 3: @@ -1809,12 +1811,11 @@ LEAF_MIPS_DSPR2(jsimd_h2v2_upsample_mips_dspr2) bgtz t4, 2b addiu t5, 2 3: - ulw t6, 0(t7) // t6 = outptr - ulw t5, 4(t7) // t5 = outptr[1] + lw t6, 0(t7) // t6 = outptr[0] + lw t5, 4(t7) // t5 = outptr[1] addu t4, t6, a1 // t4 = new end address - subu t8, t4, t9 - beqz t8, 5f - nop + beq a1, t9, 5f + subu t8, t4, t9 4: ulw t0, 0(t6) ulw t1, 4(t6) diff --git a/media/update-libjpeg.sh b/media/update-libjpeg.sh new file mode 100755 index 000000000000..2a78eb948b6b --- /dev/null +++ b/media/update-libjpeg.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +set -v -e -x + +if [ $# -lt 1 ]; then + echo "Usage: update-libjpeg.sh /path/to/libjpeg-turbo/ [tag]" + exit 1 +fi + +srcdir=`realpath $(dirname $0)` +topsrcdir=${srcdir}/.. +rm -rf $srcdir/libjpeg + +repo=$1 +tag=${2-HEAD} + +(cd $repo; git archive --prefix=media/libjpeg/ $tag) | (cd $srcdir/..; tar xf -) + +cd $srcdir/libjpeg +cp win/jsimdcfg.inc simd/ + +revert_files="jconfig.h jconfigint.h moz.build Makefile.in MOZCHANGES mozilla.diff simd/jsimdcfg.inc" +if test -d ${topsrcdir}/.hg; then + hg revert --no-backup $revert_files +elif test -d ${topsrcdir}/.git; then + git checkout HEAD -- $revert_files +fi + +patch -p0 -i mozilla.diff From 865aaf3b3afdff9e8912d5875193ea240eb7c59c Mon Sep 17 00:00:00 2001 From: Alexander Surkov Date: Tue, 6 Oct 2015 12:36:47 -0400 Subject: [PATCH 056/228] Bug 873438 - Implement IAccessible2_2::accessibleWithCaret, r=yzen --- accessible/windows/ia2/ia2Accessible.cpp | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/accessible/windows/ia2/ia2Accessible.cpp b/accessible/windows/ia2/ia2Accessible.cpp index a18012649902..0867e767cbd2 100644 --- a/accessible/windows/ia2/ia2Accessible.cpp +++ b/accessible/windows/ia2/ia2Accessible.cpp @@ -18,6 +18,7 @@ #include "nsIAccessibleTypes.h" #include "mozilla/a11y/PDocAccessible.h" #include "Relation.h" +#include "nsAccessibilityService.h" #include "nsIPersistentProperties2.h" #include "nsISimpleEnumerator.h" @@ -651,7 +652,27 @@ ia2Accessible::get_accessibleWithCaret(IUnknown** aAccessible, *aAccessible = nullptr; *aCaretOffset = -1; - return E_NOTIMPL; + + AccessibleWrap* acc = static_cast(this); + if (acc->IsDefunct()) + return CO_E_OBJNOTCONNECTED; + + int32_t caretOffset = -1; + Accessible* accWithCaret = SelectionMgr()->AccessibleWithCaret(&caretOffset); + if (acc->Document() != accWithCaret->Document()) + return S_FALSE; + + Accessible* child = accWithCaret; + while (child != acc) + child = child->Parent(); + + if (!child) + return S_FALSE; + + *aAccessible = static_cast( + static_cast(accWithCaret)); + *aCaretOffset = caretOffset; + return S_OK; A11Y_TRYBLOCK_END } From 801445d7a96d57931144629504a3b8697f551d06 Mon Sep 17 00:00:00 2001 From: Jordan Lund Date: Tue, 6 Oct 2015 11:16:00 -0700 Subject: [PATCH 057/228] Bug 1210247 - create a separate tooltool manifest for b2gdroid and add custom NDK-r10e to manifest, r=dustin --HG-- rename : mobile/android/config/tooltool-manifests/android/releng.manifest => mobile/android/config/tooltool-manifests/b2gdroid/releng.manifest --- .../android/b2gdroid/config/mozconfigs/common | 6 +- .../android/releng.manifest | 7 -- .../b2gdroid/releng.manifest | 65 +++++++++++++++++++ .../64_api_11_b2gdroid.py | 2 +- 4 files changed, 69 insertions(+), 11 deletions(-) create mode 100644 mobile/android/config/tooltool-manifests/b2gdroid/releng.manifest diff --git a/mobile/android/b2gdroid/config/mozconfigs/common b/mobile/android/b2gdroid/config/mozconfigs/common index f2bdda8f6b7a..71143fd46ce2 100644 --- a/mobile/android/b2gdroid/config/mozconfigs/common +++ b/mobile/android/b2gdroid/config/mozconfigs/common @@ -29,13 +29,13 @@ MOZ_SZIP_FLAGS="-D auto -f auto" ac_add_options --enable-elf-hack -ANDROID_NDK_VERSION="r8e" -ANDROID_NDK_VERSION_32BIT="r8c" +ANDROID_NDK_VERSION="r10e" +ANDROID_NDK_VERSION_32BIT="r10c" # Build B2GDroid ac_add_options --enable-application=mobile/android/b2gdroid -ac_add_options --with-android-ndk="$topsrcdir/android-ndk" +ac_add_options --with-android-ndk="$topsrcdir/android-ndk-r10e" ac_add_options --with-android-sdk="$topsrcdir/android-sdk-linux" ac_add_options --with-android-gnu-compiler-version=4.9 diff --git a/mobile/android/config/tooltool-manifests/android/releng.manifest b/mobile/android/config/tooltool-manifests/android/releng.manifest index 89147036da42..ea25f87f77d8 100644 --- a/mobile/android/config/tooltool-manifests/android/releng.manifest +++ b/mobile/android/config/tooltool-manifests/android/releng.manifest @@ -54,12 +54,5 @@ "algorithm": "sha512", "filename": "java_home-1.7.0-openjdk-1.7.0.85.x86_64.tar.xz", "unpack": true -}, -{ -"size": 31078810, -"digest": "2dffe4e5419a0c0c9908dc52b01cc07379a42e2aa8481be7a26bb8750b586b95bbac3fe57e64f5d37b43e206516ea70ad938a2e45858fdcf1e28258e70ae8d8c", -"algorithm": "sha512", -"filename": "moz-tt.tar.bz2", -"unpack": true } ] diff --git a/mobile/android/config/tooltool-manifests/b2gdroid/releng.manifest b/mobile/android/config/tooltool-manifests/b2gdroid/releng.manifest new file mode 100644 index 000000000000..704832e942de --- /dev/null +++ b/mobile/android/config/tooltool-manifests/b2gdroid/releng.manifest @@ -0,0 +1,65 @@ +[ +{ +"size": 932378577, +"visibility": "internal", +"digest": "b42eac625027afca51ff6113c614cae5ba9d2042c8dd63dc0b48e35016e9e8ba47995d639ae4d192f2efee7de83ee410cc96bb6e9d5dab48b123c6ed7c56cec9", +"algorithm": "sha512", +"filename": "android-ndk-r10e.tgz", +"unpack": true +}, +{ +"size": 535625068, +"visibility": "internal", +"digest": "0627515046a23c1d109e2782865b1b3b546c1d552955e4156317f76cbb195eb630aa25feea3f4edd1c685f129da0c2a5169d4d6349c1c31d8a95158a4569a478", +"algorithm": "sha512", +"filename": "android-sdk-linux.tar.xz", +"unpack": true +}, +{ +"size": 167175, +"visibility": "public", +"digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831", +"algorithm": "sha512", +"filename": "sccache.tar.bz2", +"unpack": true +}, +{ +"size": 7920445, +"visibility": "public", +"digest": "e28b7a12fbbef02ad742958df8dd356ea2adb8ef79e95cd8eb8dbc953eb4cc11888969dac7d636187fd3ace9c63d9a6bc3d7795021c1d811a843e413fe5e52c9", +"algorithm": "sha512", +"filename": "apache-ant.tar.bz2", +"unpack": true +}, +{ +"size": 4906080, +"visibility": "public", +"unpack": true, +"digest": "d735544e039da89382c53b2302b7408d4610247b4f8b5cdc5a4d5a8ec5470947b19e8ea7f7a37e78222e661347e394e0030d81f41534138b527b14e9c4e55634", +"algorithm": "sha512", +"filename": "jsshell.tar.xz" +}, +{ +"size": 80458572, +"visibility": "public", +"unpack": true, +"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad", +"algorithm": "sha512", +"filename": "gcc.tar.xz" +}, +{ +"size": 31013068, +"visibility": "public", +"digest": "e30a26f98a3448064857491aee1a7a26f98494f86a89113de9be17c37c8181ed60250706fed881ec1f035002fcdaf8b9b4a7d9ae70ce40acff2f1acfbb40f8d9", +"algorithm": "sha512", +"filename": "java_home-1.7.0-openjdk-1.7.0.85.x86_64.tar.xz", +"unpack": true +}, +{ +"size": 31078810, +"digest": "2dffe4e5419a0c0c9908dc52b01cc07379a42e2aa8481be7a26bb8750b586b95bbac3fe57e64f5d37b43e206516ea70ad938a2e45858fdcf1e28258e70ae8d8c", +"algorithm": "sha512", +"filename": "moz-tt.tar.bz2", +"unpack": true +} +] diff --git a/testing/mozharness/configs/builds/releng_sub_android_configs/64_api_11_b2gdroid.py b/testing/mozharness/configs/builds/releng_sub_android_configs/64_api_11_b2gdroid.py index d46e9f8aa6e4..31c38fda6e85 100644 --- a/testing/mozharness/configs/builds/releng_sub_android_configs/64_api_11_b2gdroid.py +++ b/testing/mozharness/configs/builds/releng_sub_android_configs/64_api_11_b2gdroid.py @@ -3,6 +3,6 @@ config = { 'stage_platform': 'android-api-11-b2gdroid', 'build_type': 'api-11-b2gdroid-opt', 'src_mozconfig': 'mobile/android/b2gdroid/config/mozconfigs/nightly', - 'tooltool_manifest_src': 'mobile/android/config/tooltool-manifests/android/releng.manifest', + 'tooltool_manifest_src': 'mobile/android/config/tooltool-manifests/b2gdroid/releng.manifest', 'multi_locale_config_platform': 'android', } From 5342fc54c1dfd0dc067f10407ad793c2dd240f21 Mon Sep 17 00:00:00 2001 From: Jordan Lund Date: Tue, 6 Oct 2015 11:16:44 -0700 Subject: [PATCH 058/228] Bug 1210631 - enable b2gdroid variant across all of trunk, r=dustin --- testing/taskcluster/tasks/branches/base_jobs.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/testing/taskcluster/tasks/branches/base_jobs.yml b/testing/taskcluster/tasks/branches/base_jobs.yml index 4ee1a3e98c07..03e1494fe72b 100644 --- a/testing/taskcluster/tasks/branches/base_jobs.yml +++ b/testing/taskcluster/tasks/branches/base_jobs.yml @@ -150,6 +150,12 @@ builds: types: debug: task: tasks/builds/dbg_macosx64.yml + android-b2gdroid: + platforms: + - Android + types: + opt: + task: tasks/builds/android_api_11_b2gdroid.yml tests: cppunit: From dc17e5a1b801bd3f0f9493706cf4f690ae9a8a8d Mon Sep 17 00:00:00 2001 From: Eric Rahm Date: Tue, 6 Oct 2015 11:23:30 -0700 Subject: [PATCH 059/228] Bug 1194555 - Part 0: Cleanup GetReportsState constructor. r=njn Move GetReportsState ctor to the impl so that mChildrenPending doesn't have to be heap allocated. --- xpcom/base/nsMemoryReporterManager.cpp | 39 ++++++++++++++++++-------- xpcom/base/nsMemoryReporterManager.h | 23 ++------------- 2 files changed, 30 insertions(+), 32 deletions(-) diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp index 4deb78839699..5139ab2af36f 100644 --- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -1438,7 +1438,6 @@ nsMemoryReporterManager::GetReportsExtended( aFinishReporting, aFinishReportingData, aDMDDumpIdent); - mGetReportsState->mChildrenPending = new nsTArray>(); if (aMinimize) { rv = MinimizeMemoryUsage(NS_NewRunnableMethod( @@ -1479,7 +1478,7 @@ nsMemoryReporterManager::StartGettingReports() // to be buffered and consume (possibly scarce) memory. for (size_t i = 0; i < childWeakRefs.Length(); ++i) { - s->mChildrenPending->AppendElement(childWeakRefs[i]); + s->mChildrenPending.AppendElement(childWeakRefs[i]); } nsCOMPtr timer = do_CreateInstance(NS_TIMER_CONTRACTID); @@ -1676,29 +1675,29 @@ nsMemoryReporterManager::EndProcessReport(uint32_t aGeneration, bool aSuccess) aGeneration, s->mNumProcessesCompleted, aSuccess ? "completed" : "exited during report", s->mNumProcessesRunning, - static_cast(s->mChildrenPending->Length())); + static_cast(s->mChildrenPending.Length())); // Start pending children up to the concurrency limit. while (s->mNumProcessesRunning < s->mConcurrencyLimit && - !s->mChildrenPending->IsEmpty()) { + !s->mChildrenPending.IsEmpty()) { // Pop last element from s->mChildrenPending nsRefPtr nextChild; - nextChild.swap(s->mChildrenPending->LastElement()); - s->mChildrenPending->TruncateLength(s->mChildrenPending->Length() - 1); + nextChild.swap(s->mChildrenPending.LastElement()); + s->mChildrenPending.TruncateLength(s->mChildrenPending.Length() - 1); // Start report (if the child is still alive and not Nuwa). if (StartChildReport(nextChild, s)) { ++s->mNumProcessesRunning; MEMORY_REPORTING_LOG("HandleChildReports (aGen=%u): started child report" " (%u running, %u pending)\n", aGeneration, s->mNumProcessesRunning, - static_cast(s->mChildrenPending->Length())); + static_cast(s->mChildrenPending.Length())); } } // If all the child processes (if any) have reported, we can cancel // the timer (if started) and finish up. Otherwise, just return. if (s->mNumProcessesRunning == 0) { - MOZ_ASSERT(s->mChildrenPending->IsEmpty()); + MOZ_ASSERT(s->mChildrenPending.IsEmpty()); if (s->mTimer) { s->mTimer->Cancel(); } @@ -1718,7 +1717,7 @@ nsMemoryReporterManager::TimeoutCallback(nsITimer* aTimer, void* aData) MOZ_RELEASE_ASSERT(s, "mgr->mGetReportsState"); MEMORY_REPORTING_LOG("TimeoutCallback (s->gen=%u; %u running, %u pending)\n", s->mGeneration, s->mNumProcessesRunning, - static_cast(s->mChildrenPending->Length())); + static_cast(s->mChildrenPending.Length())); // We don't bother sending any kind of cancellation message to the child // processes that haven't reported back. @@ -1749,9 +1748,27 @@ nsMemoryReporterManager::FinishReporting() return rv; } -nsMemoryReporterManager::GetReportsState::~GetReportsState() +nsMemoryReporterManager::GetReportsState::GetReportsState( + uint32_t aGeneration, bool aAnonymize, bool aMinimize, + uint32_t aConcurrencyLimit, + nsIHandleReportCallback* aHandleReport, + nsISupports* aHandleReportData, + nsIFinishReportingCallback* aFinishReporting, + nsISupports* aFinishReportingData, + const nsAString& aDMDDumpIdent) + : mGeneration(aGeneration) + , mAnonymize(aAnonymize) + , mMinimize(aMinimize) + , mChildrenPending() + , mNumProcessesRunning(1) // reporting starts with the parent + , mNumProcessesCompleted(0) + , mConcurrencyLimit(aConcurrencyLimit) + , mHandleReport(aHandleReport) + , mHandleReportData(aHandleReportData) + , mFinishReporting(aFinishReporting) + , mFinishReportingData(aFinishReportingData) + , mDMDDumpIdent(aDMDDumpIdent) { - delete mChildrenPending; } static void diff --git a/xpcom/base/nsMemoryReporterManager.h b/xpcom/base/nsMemoryReporterManager.h index 152e83a69b13..4adfa60b80a6 100644 --- a/xpcom/base/nsMemoryReporterManager.h +++ b/xpcom/base/nsMemoryReporterManager.h @@ -211,10 +211,7 @@ private: bool mAnonymize; bool mMinimize; nsCOMPtr mTimer; - // This is a pointer to an nsTArray because otherwise C++ is - // unhappy unless this header includes ContentParent.h, which not - // everything that includes this header knows how to find. - nsTArray>* mChildrenPending; + nsTArray> mChildrenPending; uint32_t mNumProcessesRunning; uint32_t mNumProcessesCompleted; uint32_t mConcurrencyLimit; @@ -230,23 +227,7 @@ private: nsISupports* aHandleReportData, nsIFinishReportingCallback* aFinishReporting, nsISupports* aFinishReportingData, - const nsAString& aDMDDumpIdent) - : mGeneration(aGeneration) - , mAnonymize(aAnonymize) - , mMinimize(aMinimize) - , mChildrenPending(nullptr) - , mNumProcessesRunning(1) // reporting starts with the parent - , mNumProcessesCompleted(0) - , mConcurrencyLimit(aConcurrencyLimit) - , mHandleReport(aHandleReport) - , mHandleReportData(aHandleReportData) - , mFinishReporting(aFinishReporting) - , mFinishReportingData(aFinishReportingData) - , mDMDDumpIdent(aDMDDumpIdent) - { - } - - ~GetReportsState(); + const nsAString& aDMDDumpIdent); }; // When this is non-null, a request is in flight. Note: We use manual From e15a1912e0c23959a7b69d31916abe03872727cb Mon Sep 17 00:00:00 2001 From: Eric Rahm Date: Tue, 6 Oct 2015 11:23:31 -0700 Subject: [PATCH 060/228] Bug 1194555 - Part 1: Remove RunReportersForThisProcess. r=njn RunReportersForThisProcess is no longer used and will no longer work once we have async reporters. --- xpcom/base/nsIMemoryReporter.idl | 9 ------ xpcom/base/nsMemoryReporterManager.cpp | 42 -------------------------- 2 files changed, 51 deletions(-) diff --git a/xpcom/base/nsIMemoryReporter.idl b/xpcom/base/nsIMemoryReporter.idl index 39e3be823b18..5ff894112593 100644 --- a/xpcom/base/nsIMemoryReporter.idl +++ b/xpcom/base/nsIMemoryReporter.idl @@ -520,15 +520,6 @@ nsresult RegisterNonJSSizeOfTab(NonJSSizeOfTabFn aSizeOfTabFn); } #if defined(MOZ_DMD) && !defined(MOZILLA_XPCOMRT_API) -namespace mozilla { -namespace dmd { -// This runs all the memory reporters in the current process but does nothing -// with the results; i.e. it does the minimal amount of work possible for DMD -// to do its thing. It does nothing with child processes. -void RunReportersForThisProcess(); -} -} - #if !defined(MOZ_MEMORY) #error "MOZ_DMD requires MOZ_MEMORY" #endif diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp index 5139ab2af36f..69db11fc37c4 100644 --- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -2500,45 +2500,3 @@ DEFINE_REGISTER_SIZE_OF_TAB(NonJS); #undef GET_MEMORY_REPORTER_MANAGER } // namespace mozilla - -#if defined(MOZ_DMD) - -namespace mozilla { -namespace dmd { - -class DoNothingCallback final : public nsIHandleReportCallback -{ -public: - NS_DECL_ISUPPORTS - - NS_IMETHOD Callback(const nsACString& aProcess, const nsACString& aPath, - int32_t aKind, int32_t aUnits, int64_t aAmount, - const nsACString& aDescription, - nsISupports* aData) override - { - // Do nothing; the reporter has already reported to DMD. - return NS_OK; - } - -private: - ~DoNothingCallback() {} -}; - -NS_IMPL_ISUPPORTS(DoNothingCallback, nsIHandleReportCallback) - -void -RunReportersForThisProcess() -{ - nsCOMPtr mgr = - do_GetService("@mozilla.org/memory-reporter-manager;1"); - - nsRefPtr doNothing = new DoNothingCallback(); - - mgr->GetReportsForThisProcess(doNothing, nullptr, /* anonymize = */ false); -} - -} // namespace dmd -} // namespace mozilla - -#endif // defined(MOZ_DMD) - From 57bd025868ba429286f7ec4038de7cd4548de146 Mon Sep 17 00:00:00 2001 From: Eric Rahm Date: Tue, 6 Oct 2015 11:23:32 -0700 Subject: [PATCH 061/228] Bug 1194555 - Part 2: Remove |explicit| attribute from nsIMemoryReporterManager. r=njn The calculation of |explicit| relies on the synchronous |getReportsForThisProcess|, once we have asynchronous reporters this will no longer work. As it is currently referenced in the about::memory tests we can just remove it. --- .../aboutmemory/tests/test_aboutmemory.xul | 15 ---- .../tests/test_memoryReporters.xul | 26 ++----- xpcom/base/nsIMemoryReporter.idl | 8 +- xpcom/base/nsMemoryReporterManager.cpp | 78 ------------------- 4 files changed, 9 insertions(+), 118 deletions(-) diff --git a/toolkit/components/aboutmemory/tests/test_aboutmemory.xul b/toolkit/components/aboutmemory/tests/test_aboutmemory.xul index d00e1ae1538b..8c5a9945dafd 100644 --- a/toolkit/components/aboutmemory/tests/test_aboutmemory.xul +++ b/toolkit/components/aboutmemory/tests/test_aboutmemory.xul @@ -119,21 +119,6 @@ mgr.registerStrongReporterEvenIfBlocked(fakeReporters[i]); } - // mgr.explicit sums "heap-allocated" and all the appropriate NONHEAP ones: - // - "explicit/c", "explicit/cc" x 2, "explicit/d", "explicit/e" - // - but *not* "explicit/c/d" x 2 - // Check explicit now before we add the fake reporters for the fake 2nd - // and subsequent processes. - // - // Nb: mgr.explicit will throw NS_ERROR_NOT_AVAILABLE if this is a - // --disable-jemalloc build. Allow for that exception, but *only* that - // exception. - try { - is(mgr.explicit, 500*MB + (100 + 13 + 10)*MB + 599*KB, "mgr.explicit"); - } catch (ex) { - is(ex.result, Cr.NS_ERROR_NOT_AVAILABLE, "mgr.explicit exception"); - } - // The main process always comes first when we display about:memory. The // remaining processes are sorted by their |resident| values (starting with // the largest). Processes without a |resident| memory reporter are saved diff --git a/toolkit/components/aboutmemory/tests/test_memoryReporters.xul b/toolkit/components/aboutmemory/tests/test_memoryReporters.xul index d9f1b81064e3..5a96c3bd4cac 100644 --- a/toolkit/components/aboutmemory/tests/test_memoryReporters.xul +++ b/toolkit/components/aboutmemory/tests/test_memoryReporters.xul @@ -141,21 +141,6 @@ let mgr = Cc["@mozilla.org/memory-reporter-manager;1"]. getService(Ci.nsIMemoryReporterManager); - // Access the distinguished amounts (mgr.explicit et al.) just to make sure - // they don't crash. We can't check their actual values because they're - // non-deterministic. - // - // Nb: mgr.explicit will throw NS_ERROR_NOT_AVAILABLE if this is a - // --disable-jemalloc build. Allow for that exception, but *only* that - // exception. - let dummy; - let haveExplicit = true; - try { - dummy = mgr.explicit; - } catch (ex) { - is(ex.result, Cr.NS_ERROR_NOT_AVAILABLE, "mgr.explicit exception"); - haveExplicit = false; - } let amounts = [ "vsize", "vsizeMaxContiguous", @@ -182,7 +167,7 @@ // aren't available on all platforms. But if the attribute simply // isn't present, that indicates the distinguished amounts have changed // and this file hasn't been updated appropriately. - dummy = mgr[amounts[i]]; + let dummy = mgr[amounts[i]]; ok(dummy !== undefined, "accessed an unknown distinguished amount: " + amounts[i]); } catch (ex) { @@ -226,9 +211,14 @@ } } - // If mgr.explicit failed, we won't have "heap-allocated" either. - if (haveExplicit) { + try { + // Nb: mgr.heapAllocated will throw NS_ERROR_NOT_AVAILABLE if this is a + // --disable-jemalloc build. Allow for skipping this test on that + // exception, but *only* that exception. + let dummy = mgr.heapAllocated; checkSpecialReport("heap-allocated", heapAllocatedAmounts); + } catch (ex) { + is(ex.result, Cr.NS_ERROR_NOT_AVAILABLE, "mgr.heapAllocated exception"); } // vsize may be unreasonable if ASAN is enabled checkSpecialReport("vsize", vsizeAmounts, /*canBeUnreasonable*/true); diff --git a/xpcom/base/nsIMemoryReporter.idl b/xpcom/base/nsIMemoryReporter.idl index 5ff894112593..c6f973f5622b 100644 --- a/xpcom/base/nsIMemoryReporter.idl +++ b/xpcom/base/nsIMemoryReporter.idl @@ -205,7 +205,7 @@ interface nsIFinishReportingCallback : nsISupports void callback(in nsISupports data); }; -[scriptable, builtinclass, uuid(5e4eaa5a-4808-4b97-8005-e7cdc4d73693)] +[scriptable, builtinclass, uuid(461c477a-54f9-4fe0-b00e-1857f96690f9)] interface nsIMemoryReporterManager : nsISupports { /* @@ -325,11 +325,6 @@ interface nsIMemoryReporterManager : nsISupports * If you add a new distinguished amount, please update * toolkit/components/aboutmemory/tests/test_memoryReporters.xul. * - * |explicit| (UNITS_BYTES) The total size of explicit memory allocations, - * both at the OS-level (eg. via mmap, VirtualAlloc) and at the heap level - * (eg. via malloc, calloc, operator new). It covers all heap allocations, - * but will miss any OS-level ones not covered by memory reporters. - * * |vsize| (UNITS_BYTES) The virtual size, i.e. the amount of address space * taken up. * @@ -378,7 +373,6 @@ interface nsIMemoryReporterManager : nsISupports * |pageFaultsHard| (UNITS_COUNT_CUMULATIVE) The number of hard (a.k.a. * major) page faults that have occurred since the process started. */ - readonly attribute int64_t explicit; readonly attribute int64_t vsize; readonly attribute int64_t vsizeMaxContiguous; readonly attribute int64_t resident; diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp index 69db11fc37c4..cc506a1b5ff7 100644 --- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -1944,84 +1944,6 @@ nsMemoryReporterManager::UnblockRegistrationAndRestoreOriginalReporters() return NS_OK; } -// This is just a wrapper for int64_t that implements nsISupports, so it can be -// passed to nsIMemoryReporter::CollectReports. -class Int64Wrapper final : public nsISupports -{ - ~Int64Wrapper() {} - -public: - NS_DECL_ISUPPORTS - Int64Wrapper() : mValue(0) - { - } - int64_t mValue; -}; - -NS_IMPL_ISUPPORTS0(Int64Wrapper) - -class ExplicitCallback final : public nsIHandleReportCallback -{ - ~ExplicitCallback() {} - -public: - NS_DECL_ISUPPORTS - - NS_IMETHOD Callback(const nsACString& aProcess, const nsACString& aPath, - int32_t aKind, int32_t aUnits, int64_t aAmount, - const nsACString& aDescription, - nsISupports* aWrappedExplicit) override - { - // Using the "heap-allocated" reporter here instead of - // nsMemoryReporterManager.heapAllocated goes against the usual - // pattern. But it's for a good reason: in tests, we can easily - // create artificial (i.e. deterministic) reporters -- which allows us - // to precisely test nsMemoryReporterManager.explicit -- but we can't - // do that for distinguished amounts. - if (aPath.EqualsLiteral("heap-allocated") || - (aKind == nsIMemoryReporter::KIND_NONHEAP && - PromiseFlatCString(aPath).Find("explicit") == 0)) { - Int64Wrapper* wrappedInt64 = static_cast(aWrappedExplicit); - wrappedInt64->mValue += aAmount; - } - return NS_OK; - } -}; - -NS_IMPL_ISUPPORTS(ExplicitCallback, nsIHandleReportCallback) - -NS_IMETHODIMP -nsMemoryReporterManager::GetExplicit(int64_t* aAmount) -{ - if (NS_WARN_IF(!aAmount)) { - return NS_ERROR_INVALID_ARG; - } - *aAmount = 0; -#ifndef HAVE_JEMALLOC_STATS - return NS_ERROR_NOT_AVAILABLE; -#else - - // For each reporter we call CollectReports and filter out the - // non-explicit, non-NONHEAP measurements (except for "heap-allocated"). - // That's lots of wasted work, and we used to have a GetExplicitNonHeap() - // method which did this more efficiently, but it ended up being more - // trouble than it was worth. - - nsRefPtr handleReport = new ExplicitCallback(); - nsRefPtr wrappedExplicitSize = new Int64Wrapper(); - - // Anonymization doesn't matter here, because we're only summing all the - // reported values. Enable it anyway because it's slightly faster, since it - // doesn't have to get URLs, find notable strings, etc. - GetReportsForThisProcess(handleReport, wrappedExplicitSize, - /* anonymize = */ true); - - *aAmount = wrappedExplicitSize->mValue; - - return NS_OK; -#endif // HAVE_JEMALLOC_STATS -} - NS_IMETHODIMP nsMemoryReporterManager::GetVsize(int64_t* aVsize) { From 16b67b6d6cf9659783c0bd3af3dd2907203d6b56 Mon Sep 17 00:00:00 2001 From: Eric Rahm Date: Tue, 6 Oct 2015 11:23:33 -0700 Subject: [PATCH 062/228] Bug 1194555 - Part 3: Remove |getReportsForThisProcess| from the nsIMemoryReporterManager interface. r=njn |getReportsForThisProcess| differs from |getReports| in that it is limited to current process and is synchronous. When asynchronous memory reporters are added the function will no longer be able tobe synchronous. There isn't much utility in only measuring the current process, so we can remove the function and switch existing users to |getReports|. --- image/test/mochitest/test_bug601470.html | 11 +- .../tests/test_memoryReporters.xul | 149 +++++++++++------- .../tests/test_sqliteMultiReporter.xul | 13 +- xpcom/base/nsIMemoryReporter.idl | 15 +- xpcom/base/nsMemoryReporterManager.cpp | 9 -- 5 files changed, 108 insertions(+), 89 deletions(-) diff --git a/image/test/mochitest/test_bug601470.html b/image/test/mochitest/test_bug601470.html index fea2424b2a45..a9e1cc7880e9 100644 --- a/image/test/mochitest/test_bug601470.html +++ b/image/test/mochitest/test_bug601470.html @@ -30,12 +30,13 @@ window.onload = function() { amount += aAmount; } - mgr.getReportsForThisProcess(handleReport, null, /* anonymize = */ false); + var finished = function() { + ok(amount > 0, "we should be using a nonzero amount of memory"); + ok(true, "yay, didn't crash!"); + SimpleTest.finish(); + } - ok(amount > 0, "we should be using a nonzero amount of memory"); - ok(true, "yay, didn't crash!"); - - SimpleTest.finish(); + mgr.getReports(handleReport, null, finished, null, /* anonymize = */ false); } diff --git a/toolkit/components/aboutmemory/tests/test_memoryReporters.xul b/toolkit/components/aboutmemory/tests/test_memoryReporters.xul index 5a96c3bd4cac..035bb05ed48e 100644 --- a/toolkit/components/aboutmemory/tests/test_memoryReporters.xul +++ b/toolkit/components/aboutmemory/tests/test_memoryReporters.xul @@ -44,6 +44,8 @@ const XUL_NS = "http:\\\\www.mozilla.org\\keymaster\\gatekeeper\\there.is.only.xul"; + SimpleTest.waitForExplicitFinish(); + let vsizeAmounts = []; let residentAmounts = []; let heapAllocatedAmounts = []; @@ -189,11 +191,33 @@ domSize, styleSize, otherSize, totalSize, jsMilliseconds, nonJSMilliseconds); - mgr.getReportsForThisProcess(handleReportNormal, null, - /* anonymize = */ false); + let asyncSteps = [ + getReportsNormal, + getReportsAnonymized, + checkResults, + test_register_strong, + test_register_strong, // Make sure re-registering works + test_register_weak, + SimpleTest.finish + ]; - mgr.getReportsForThisProcess(handleReportAnonymized, null, - /* anonymize = */ true); + function runNext() { + setTimeout(asyncSteps.shift(), 0); + } + + function getReportsNormal() + { + mgr.getReports(handleReportNormal, null, + runNext, null, + /* anonymize = */ false); + } + + function getReportsAnonymized() + { + mgr.getReports(handleReportAnonymized, null, + runNext, null, + /* anonymize = */ true); + } function checkSizeReasonable(aName, aAmount) { @@ -211,45 +235,50 @@ } } - try { - // Nb: mgr.heapAllocated will throw NS_ERROR_NOT_AVAILABLE if this is a - // --disable-jemalloc build. Allow for skipping this test on that - // exception, but *only* that exception. - let dummy = mgr.heapAllocated; - checkSpecialReport("heap-allocated", heapAllocatedAmounts); - } catch (ex) { - is(ex.result, Cr.NS_ERROR_NOT_AVAILABLE, "mgr.heapAllocated exception"); + function checkResults() + { + try { + // Nb: mgr.heapAllocated will throw NS_ERROR_NOT_AVAILABLE if this is a + // --disable-jemalloc build. Allow for skipping this test on that + // exception, but *only* that exception. + let dummy = mgr.heapAllocated; + checkSpecialReport("heap-allocated", heapAllocatedAmounts); + } catch (ex) { + is(ex.result, Cr.NS_ERROR_NOT_AVAILABLE, "mgr.heapAllocated exception"); + } + // vsize may be unreasonable if ASAN is enabled + checkSpecialReport("vsize", vsizeAmounts, /*canBeUnreasonable*/true); + checkSpecialReport("resident", residentAmounts); + + for (var reporter in jsGcHeapUsedGcThings) { + ok(jsGcHeapUsedGcThings[reporter] == 1); + } + checkSizeReasonable("js-main-runtime-gc-heap-committed/used/gc-things", + jsGcHeapUsedGcThingsTotal); + + ok(present.jsNonWindowCompartments, "js-non-window compartments are present"); + ok(present.windowObjectsJsCompartments, "window-objects/.../js compartments are present"); + ok(present.places, "places is present"); + ok(present.images, "images is present"); + ok(present.xptiWorkingSet, "xpti-working-set is present"); + ok(present.atomTablesMain, "atom-tables/main is present"); + ok(present.sandboxLocation, "sandbox locations are present"); + ok(present.bigString, "large string is present"); + ok(present.smallString1, "small string 1 is present"); + ok(present.smallString2, "small string 2 is present"); + + ok(!present.anonymizedWhenUnnecessary, + "anonymized paths are not present when unnecessary. Failed case: " + + present.anonymizedWhenUnnecessary); + ok(!present.httpWhenAnonymized, + "http URLs are anonymized when necessary. Failed case: " + + present.httpWhenAnonymized); + ok(!present.unanonymizedFilePathWhenAnonymized, + "file URLs are anonymized when necessary. Failed case: " + + present.unanonymizedFilePathWhenAnonymized); + + runNext(); } - // vsize may be unreasonable if ASAN is enabled - checkSpecialReport("vsize", vsizeAmounts, /*canBeUnreasonable*/true); - checkSpecialReport("resident", residentAmounts); - - for (var reporter in jsGcHeapUsedGcThings) { - ok(jsGcHeapUsedGcThings[reporter] == 1); - } - checkSizeReasonable("js-main-runtime-gc-heap-committed/used/gc-things", - jsGcHeapUsedGcThingsTotal); - - ok(present.jsNonWindowCompartments, "js-non-window compartments are present"); - ok(present.windowObjectsJsCompartments, "window-objects/.../js compartments are present"); - ok(present.places, "places is present"); - ok(present.images, "images is present"); - ok(present.xptiWorkingSet, "xpti-working-set is present"); - ok(present.atomTablesMain, "atom-tables/main is present"); - ok(present.sandboxLocation, "sandbox locations are present"); - ok(present.bigString, "large string is present"); - ok(present.smallString1, "small string 1 is present"); - ok(present.smallString2, "small string 2 is present"); - - ok(!present.anonymizedWhenUnnecessary, - "anonymized paths are not present when unnecessary. Failed case: " + - present.anonymizedWhenUnnecessary); - ok(!present.httpWhenAnonymized, - "http URLs are anonymized when necessary. Failed case: " + - present.httpWhenAnonymized); - ok(!present.unanonymizedFilePathWhenAnonymized, - "file URLs are anonymized when necessary. Failed case: " + - present.unanonymizedFilePathWhenAnonymized); // Reporter registration tests @@ -342,27 +371,28 @@ mgr.registerStrongReporter(reporterAndCallback); // Check the generated reports. - mgr.getReportsForThisProcess(reporterAndCallback, null, - /* anonymize = */ false); - reporterAndCallback.finish(); + mgr.getReports(reporterAndCallback, null, + () => { + reporterAndCallback.finish(); + window.setTimeout(test_unregister_strong, 0, reporterAndCallback); + }, null, + /* anonymize = */ false); + } - // Unregistration works. - mgr.unregisterStrongReporter(reporterAndCallback); + function test_unregister_strong(aReporterAndCallback) + { + mgr.unregisterStrongReporter(aReporterAndCallback); // The reporter was unregistered, hence there shouldn't be any reports from // the test reporter. - mgr.getReportsForThisProcess(reporterAndCallback, null, - /* anonymize = */ false); - reporterAndCallback.finish(0); + mgr.getReports(aReporterAndCallback, null, + () => { + aReporterAndCallback.finish(0); + runNext(); + }, null, + /* anonymize = */ false); } - test_register_strong(); - - // Check strong reporters a second time, to make sure a reporter can be - // re-registered. - test_register_strong(); - - // Check that you cannot register JS components as weak reporters. function test_register_weak() { let reporterAndCallback = new MemoryReporterAndCallback(); @@ -382,9 +412,12 @@ ok(ex.message.indexOf("NS_ERROR_") >= 0, "WrappedJS reporter got rejected: " + ex); } + + runNext(); } - test_register_weak(); + // Kick-off the async tests. + runNext(); ]]> diff --git a/toolkit/components/aboutmemory/tests/test_sqliteMultiReporter.xul b/toolkit/components/aboutmemory/tests/test_sqliteMultiReporter.xul index 29c85a5c72a8..3452bbbc7205 100644 --- a/toolkit/components/aboutmemory/tests/test_sqliteMultiReporter.xul +++ b/toolkit/components/aboutmemory/tests/test_sqliteMultiReporter.xul @@ -24,6 +24,8 @@ const Ci = Components.interfaces; const Cu = Components.utils; + SimpleTest.waitForExplicitFinish(); + // Make a fake DB file. let file = Cc["@mozilla.org/file/directory_service;1"]. getService(Ci.nsIProperties). @@ -40,11 +42,12 @@ // them. It shouldn't crash. let mgr = Cc["@mozilla.org/memory-reporter-manager;1"]. getService(Ci.nsIMemoryReporterManager); - mgr.getReportsForThisProcess(function(){}, null, /* anonymize = */ false); - - // If we haven't crashed, we've passed, but the test harness requires that - // we explicitly check something. - ok(true, "didn't crash"); + mgr.getReports(function(){}, null, + () => { + ok(true, "didn't crash"); + SimpleTest.finish(); + }, null, + /* anonymize = */ false); ]]> diff --git a/xpcom/base/nsIMemoryReporter.idl b/xpcom/base/nsIMemoryReporter.idl index c6f973f5622b..9a17c89957eb 100644 --- a/xpcom/base/nsIMemoryReporter.idl +++ b/xpcom/base/nsIMemoryReporter.idl @@ -205,7 +205,7 @@ interface nsIFinishReportingCallback : nsISupports void callback(in nsISupports data); }; -[scriptable, builtinclass, uuid(461c477a-54f9-4fe0-b00e-1857f96690f9)] +[scriptable, builtinclass, uuid(6cc4aa56-e18c-4b61-9290-6297172d6978)] interface nsIMemoryReporterManager : nsISupports { /* @@ -289,14 +289,6 @@ interface nsIMemoryReporterManager : nsISupports in boolean minimizeMemoryUsage, in AString DMDDumpIdent); - /* - * Get memory reports in the current process only. |handleReport| is called - * for each report. - */ - void getReportsForThisProcess(in nsIMemoryReporterCallback handleReport, - in nsISupports handleReportData, - in boolean anonymize); - /* * As above, but if DMD is enabled and |DMDFile| is non-null then * write a DMD report to that file and close it. @@ -315,9 +307,8 @@ interface nsIMemoryReporterManager : nsISupports * interesting that we want external code (e.g. telemetry) to be able to rely * on them. * - * Note that these are not reporters and so getReports() and - * getReportsForThisProcess() do not look at them. However, distinguished - * amounts can be embedded in a reporter. + * Note that these are not reporters and so getReports() does not look at + * them. However, distinguished amounts can be embedded in a reporter. * * Access to these attributes can fail. In particular, some of them are not * available on all platforms. diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp index cc506a1b5ff7..7614aea1fcc1 100644 --- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -1505,15 +1505,6 @@ nsMemoryReporterManager::StartGettingReports() return NS_OK; } -NS_IMETHODIMP -nsMemoryReporterManager::GetReportsForThisProcess( - nsIHandleReportCallback* aHandleReport, - nsISupports* aHandleReportData, bool aAnonymize) -{ - return GetReportsForThisProcessExtended(aHandleReport, aHandleReportData, - aAnonymize, nullptr); -} - NS_IMETHODIMP nsMemoryReporterManager::GetReportsForThisProcessExtended( nsIHandleReportCallback* aHandleReport, nsISupports* aHandleReportData, From 6fd2bbb5e82cfd9940db4f0bfeb7f855867f423d Mon Sep 17 00:00:00 2001 From: Eric Rahm Date: Tue, 6 Oct 2015 11:23:34 -0700 Subject: [PATCH 063/228] Bug 1194555 - Part 4: Rename GetReportsState PendingProcessesState. r=njn --- xpcom/base/nsMemoryReporterManager.cpp | 58 +++++++++++++------------- xpcom/base/nsMemoryReporterManager.h | 26 ++++++------ 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp index 7614aea1fcc1..243c12055e3b 100644 --- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -1356,7 +1356,7 @@ nsMemoryReporterManager::nsMemoryReporterManager() , mSavedStrongReporters(nullptr) , mSavedWeakReporters(nullptr) , mNextGeneration(1) - , mGetReportsState(nullptr) + , mPendingProcessesState(nullptr) { } @@ -1414,11 +1414,11 @@ nsMemoryReporterManager::GetReportsExtended( uint32_t generation = mNextGeneration++; - if (mGetReportsState) { + if (mPendingProcessesState) { // A request is in flight. Don't start another one. And don't report // an error; just ignore it, and let the in-flight request finish. MEMORY_REPORTING_LOG("GetReports (gen=%u, s->gen=%u): abort\n", - generation, mGetReportsState->mGeneration); + generation, mPendingProcessesState->mGeneration); return NS_OK; } @@ -1429,15 +1429,15 @@ nsMemoryReporterManager::GetReportsExtended( if (concurrency < 1) { concurrency = 1; } - mGetReportsState = new GetReportsState(generation, - aAnonymize, - aMinimize, - concurrency, - aHandleReport, - aHandleReportData, - aFinishReporting, - aFinishReportingData, - aDMDDumpIdent); + mPendingProcessesState = new PendingProcessesState(generation, + aAnonymize, + aMinimize, + concurrency, + aHandleReport, + aHandleReportData, + aFinishReporting, + aFinishReportingData, + aDMDDumpIdent); if (aMinimize) { rv = MinimizeMemoryUsage(NS_NewRunnableMethod( @@ -1451,7 +1451,7 @@ nsMemoryReporterManager::GetReportsExtended( nsresult nsMemoryReporterManager::StartGettingReports() { - GetReportsState* s = mGetReportsState; + PendingProcessesState* s = mPendingProcessesState; nsresult rv; // Get reports for this process. @@ -1552,13 +1552,13 @@ nsMemoryReporterManager::GetReportsForThisProcessExtended( return NS_OK; } -nsMemoryReporterManager::GetReportsState* +nsMemoryReporterManager::PendingProcessesState* nsMemoryReporterManager::GetStateForGeneration(uint32_t aGeneration) { // Memory reporting only happens on the main thread. MOZ_RELEASE_ASSERT(NS_IsMainThread()); - GetReportsState* s = mGetReportsState; + PendingProcessesState* s = mPendingProcessesState; if (!s) { // If we reach here, then: @@ -1595,7 +1595,7 @@ nsMemoryReporterManager::HandleChildReport( uint32_t aGeneration, const dom::MemoryReport& aChildReport) { - GetReportsState* s = GetStateForGeneration(aGeneration); + PendingProcessesState* s = GetStateForGeneration(aGeneration); if (!s) { return; } @@ -1615,7 +1615,7 @@ nsMemoryReporterManager::HandleChildReport( /* static */ bool nsMemoryReporterManager::StartChildReport(mozilla::dom::ContentParent* aChild, - const GetReportsState* aState) + const PendingProcessesState* aState) { #ifdef MOZ_NUWA_PROCESS if (aChild->IsNuwaProcess()) { @@ -1653,7 +1653,7 @@ nsMemoryReporterManager::StartChildReport(mozilla::dom::ContentParent* aChild, void nsMemoryReporterManager::EndProcessReport(uint32_t aGeneration, bool aSuccess) { - GetReportsState* s = GetStateForGeneration(aGeneration); + PendingProcessesState* s = GetStateForGeneration(aGeneration); if (!s) { return; } @@ -1700,12 +1700,12 @@ nsMemoryReporterManager::EndProcessReport(uint32_t aGeneration, bool aSuccess) nsMemoryReporterManager::TimeoutCallback(nsITimer* aTimer, void* aData) { nsMemoryReporterManager* mgr = static_cast(aData); - GetReportsState* s = mgr->mGetReportsState; + PendingProcessesState* s = mgr->mPendingProcessesState; // Release assert because: if the pointer is null we're about to // crash regardless of DEBUG, and this way the compiler doesn't // complain about unused variables. - MOZ_RELEASE_ASSERT(s, "mgr->mGetReportsState"); + MOZ_RELEASE_ASSERT(s, "mgr->mPendingProcessesState"); MEMORY_REPORTING_LOG("TimeoutCallback (s->gen=%u; %u running, %u pending)\n", s->mGeneration, s->mNumProcessesRunning, static_cast(s->mChildrenPending.Length())); @@ -1723,23 +1723,23 @@ nsMemoryReporterManager::FinishReporting() MOZ_CRASH(); } - MOZ_ASSERT(mGetReportsState); + MOZ_ASSERT(mPendingProcessesState); MEMORY_REPORTING_LOG("FinishReporting (s->gen=%u; %u processes reported)\n", - mGetReportsState->mGeneration, - mGetReportsState->mNumProcessesCompleted); + mPendingProcessesState->mGeneration, + mPendingProcessesState->mNumProcessesCompleted); - // Call this before deleting |mGetReportsState|. That way, if + // Call this before deleting |mPendingProcessesState|. That way, if // |mFinishReportData| calls GetReports(), it will silently abort, as // required. - nsresult rv = mGetReportsState->mFinishReporting->Callback( - mGetReportsState->mFinishReportingData); + nsresult rv = mPendingProcessesState->mFinishReporting->Callback( + mPendingProcessesState->mFinishReportingData); - delete mGetReportsState; - mGetReportsState = nullptr; + delete mPendingProcessesState; + mPendingProcessesState = nullptr; return rv; } -nsMemoryReporterManager::GetReportsState::GetReportsState( +nsMemoryReporterManager::PendingProcessesState::PendingProcessesState( uint32_t aGeneration, bool aAnonymize, bool aMinimize, uint32_t aConcurrencyLimit, nsIHandleReportCallback* aHandleReport, diff --git a/xpcom/base/nsMemoryReporterManager.h b/xpcom/base/nsMemoryReporterManager.h index 4adfa60b80a6..7f17b348a1d6 100644 --- a/xpcom/base/nsMemoryReporterManager.h +++ b/xpcom/base/nsMemoryReporterManager.h @@ -48,7 +48,7 @@ public: // // - GetReports() (declared within NS_DECL_NSIMEMORYREPORTERMANAGER) // synchronously gets memory reports for the current process, sets up some - // state (mGetReportsState) for when child processes report back -- + // state (mPendingProcessesState) for when child processes report back -- // including a timer -- and starts telling child processes to get memory // reports. Control then returns to the main event loop. // @@ -108,7 +108,7 @@ public: // is incomplete. // // Now, what what happens if a child process is created/destroyed in the - // middle of a request? Well, GetReportsState is initialized with an array + // middle of a request? Well, PendingProcessesState is initialized with an array // of child process actors as of when the report started. So... // // - If a process is created after reporting starts, it won't be sent a @@ -205,7 +205,7 @@ private: uint32_t mNextGeneration; - struct GetReportsState + struct PendingProcessesState { uint32_t mGeneration; bool mAnonymize; @@ -221,23 +221,23 @@ private: nsCOMPtr mFinishReportingData; nsString mDMDDumpIdent; - GetReportsState(uint32_t aGeneration, bool aAnonymize, bool aMinimize, - uint32_t aConcurrencyLimit, - nsIHandleReportCallback* aHandleReport, - nsISupports* aHandleReportData, - nsIFinishReportingCallback* aFinishReporting, - nsISupports* aFinishReportingData, - const nsAString& aDMDDumpIdent); + PendingProcessesState(uint32_t aGeneration, bool aAnonymize, bool aMinimize, + uint32_t aConcurrencyLimit, + nsIHandleReportCallback* aHandleReport, + nsISupports* aHandleReportData, + nsIFinishReportingCallback* aFinishReporting, + nsISupports* aFinishReportingData, + const nsAString& aDMDDumpIdent); }; // When this is non-null, a request is in flight. Note: We use manual // new/delete for this because its lifetime doesn't match block scope or // anything like that. - GetReportsState* mGetReportsState; + PendingProcessesState* mPendingProcessesState; - GetReportsState* GetStateForGeneration(uint32_t aGeneration); + PendingProcessesState* GetStateForGeneration(uint32_t aGeneration); static bool StartChildReport(mozilla::dom::ContentParent* aChild, - const GetReportsState* aState); + const PendingProcessesState* aState); }; #define NS_MEMORY_REPORTER_MANAGER_CID \ From d3e60f2da6d08d0bba8ae7301086249789c28a63 Mon Sep 17 00:00:00 2001 From: Eric Rahm Date: Tue, 6 Oct 2015 11:23:35 -0700 Subject: [PATCH 064/228] Bug 1194555 - Part 5: Add option for async memory reporters. r=njn --- xpcom/base/nsIMemoryReporter.idl | 6 +- xpcom/base/nsMemoryReporterManager.cpp | 141 ++++++++++++++----------- xpcom/base/nsMemoryReporterManager.h | 6 +- 3 files changed, 87 insertions(+), 66 deletions(-) diff --git a/xpcom/base/nsIMemoryReporter.idl b/xpcom/base/nsIMemoryReporter.idl index 9a17c89957eb..bcfb4e3acc66 100644 --- a/xpcom/base/nsIMemoryReporter.idl +++ b/xpcom/base/nsIMemoryReporter.idl @@ -205,7 +205,7 @@ interface nsIFinishReportingCallback : nsISupports void callback(in nsISupports data); }; -[scriptable, builtinclass, uuid(6cc4aa56-e18c-4b61-9290-6297172d6978)] +[scriptable, builtinclass, uuid(babbadb0-b22d-4b05-9ca9-01e617828ec1)] interface nsIMemoryReporterManager : nsISupports { /* @@ -220,6 +220,7 @@ interface nsIMemoryReporterManager : nsISupports * unregisterStrongReporter() at any point. */ void registerStrongReporter(in nsIMemoryReporter reporter); + void registerStrongAsyncReporter(in nsIMemoryReporter reporter); /* * Like registerReporter, but the Manager service will hold a weak reference @@ -229,6 +230,7 @@ interface nsIMemoryReporterManager : nsISupports * register your JavaScript components with registerStrongReporter(). */ void registerWeakReporter(in nsIMemoryReporter reporter); + void registerWeakAsyncReporter(in nsIMemoryReporter reporter); /* * Unregister the given memory reporter, which must have been registered with @@ -444,10 +446,12 @@ namespace mozilla { // Register a memory reporter. The manager service will hold a strong // reference to this reporter. XPCOM_API(nsresult) RegisterStrongMemoryReporter(nsIMemoryReporter* aReporter); +XPCOM_API(nsresult) RegisterStrongAsyncMemoryReporter(nsIMemoryReporter* aReporter); // Register a memory reporter. The manager service will hold a weak reference // to this reporter. XPCOM_API(nsresult) RegisterWeakMemoryReporter(nsIMemoryReporter* aReporter); +XPCOM_API(nsresult) RegisterWeakAsyncMemoryReporter(nsIMemoryReporter* aReporter); // Unregister a strong memory reporter. XPCOM_API(nsresult) UnregisterStrongMemoryReporter(nsIMemoryReporter* aReporter); diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp index 243c12055e3b..21582ff43a1b 100644 --- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -1530,12 +1530,10 @@ nsMemoryReporterManager::GetReportsForThisProcessExtended( { mozilla::MutexAutoLock autoLock(mMutex); for (auto iter = mStrongReporters->Iter(); !iter.Done(); iter.Next()) { - nsRefPtrHashKey* entry = iter.Get(); - allReporters.AppendElement(entry->GetKey()); + allReporters.AppendElement(iter.Key()); } for (auto iter = mWeakReporters->Iter(); !iter.Done(); iter.Next()) { - nsPtrHashKey* entry = iter.Get(); - allReporters.AppendElement(entry->GetKey()); + allReporters.AppendElement(iter.Key()); } } for (uint32_t i = 0; i < allReporters.Length(); i++) { @@ -1775,7 +1773,7 @@ CrashIfRefcountIsZero(nsISupports* aObj) nsresult nsMemoryReporterManager::RegisterReporterHelper( - nsIMemoryReporter* aReporter, bool aForce, bool aStrong) + nsIMemoryReporter* aReporter, bool aForce, bool aStrong, bool aIsAsync) { // This method is thread-safe. mozilla::MutexAutoLock autoLock(mMutex); @@ -1802,7 +1800,7 @@ nsMemoryReporterManager::RegisterReporterHelper( // if (aStrong) { nsCOMPtr kungFuDeathGrip = aReporter; - mStrongReporters->PutEntry(aReporter); + mStrongReporters->Put(aReporter, aIsAsync); CrashIfRefcountIsZero(aReporter); } else { CrashIfRefcountIsZero(aReporter); @@ -1815,7 +1813,7 @@ nsMemoryReporterManager::RegisterReporterHelper( // CollectReports(). return NS_ERROR_XPC_BAD_CONVERT_JS; } - mWeakReporters->PutEntry(aReporter); + mWeakReporters->Put(aReporter, aIsAsync); } return NS_OK; @@ -1825,14 +1823,32 @@ NS_IMETHODIMP nsMemoryReporterManager::RegisterStrongReporter(nsIMemoryReporter* aReporter) { return RegisterReporterHelper(aReporter, /* force = */ false, - /* strong = */ true); + /* strong = */ true, + /* async = */ false); +} + +NS_IMETHODIMP +nsMemoryReporterManager::RegisterStrongAsyncReporter(nsIMemoryReporter* aReporter) +{ + return RegisterReporterHelper(aReporter, /* force = */ false, + /* strong = */ true, + /* async = */ true); } NS_IMETHODIMP nsMemoryReporterManager::RegisterWeakReporter(nsIMemoryReporter* aReporter) { return RegisterReporterHelper(aReporter, /* force = */ false, - /* strong = */ false); + /* strong = */ false, + /* async = */ false); +} + +NS_IMETHODIMP +nsMemoryReporterManager::RegisterWeakAsyncReporter(nsIMemoryReporter* aReporter) +{ + return RegisterReporterHelper(aReporter, /* force = */ false, + /* strong = */ false, + /* async = */ true); } NS_IMETHODIMP @@ -1840,7 +1856,8 @@ nsMemoryReporterManager::RegisterStrongReporterEvenIfBlocked( nsIMemoryReporter* aReporter) { return RegisterReporterHelper(aReporter, /* force = */ true, - /* strong = */ true); + /* strong = */ true, + /* async = */ false); } NS_IMETHODIMP @@ -1852,7 +1869,7 @@ nsMemoryReporterManager::UnregisterStrongReporter(nsIMemoryReporter* aReporter) MOZ_ASSERT(!mWeakReporters->Contains(aReporter)); if (mStrongReporters->Contains(aReporter)) { - mStrongReporters->RemoveEntry(aReporter); + mStrongReporters->Remove(aReporter); return NS_OK; } @@ -1861,7 +1878,7 @@ nsMemoryReporterManager::UnregisterStrongReporter(nsIMemoryReporter* aReporter) // references that these reporters aren't expecting (which can keep them // alive longer than intended). if (mSavedStrongReporters && mSavedStrongReporters->Contains(aReporter)) { - mSavedStrongReporters->RemoveEntry(aReporter); + mSavedStrongReporters->Remove(aReporter); return NS_OK; } @@ -1877,7 +1894,7 @@ nsMemoryReporterManager::UnregisterWeakReporter(nsIMemoryReporter* aReporter) MOZ_ASSERT(!mStrongReporters->Contains(aReporter)); if (mWeakReporters->Contains(aReporter)) { - mWeakReporters->RemoveEntry(aReporter); + mWeakReporters->Remove(aReporter); return NS_OK; } @@ -1886,7 +1903,7 @@ nsMemoryReporterManager::UnregisterWeakReporter(nsIMemoryReporter* aReporter) // references that the old reporters aren't expecting (which can end up as // dangling pointers that lead to use-after-frees). if (mSavedWeakReporters && mSavedWeakReporters->Contains(aReporter)) { - mSavedWeakReporters->RemoveEntry(aReporter); + mSavedWeakReporters->Remove(aReporter); return NS_OK; } @@ -2303,54 +2320,6 @@ nsMemoryReporterManager::SizeOfTab(nsIDOMWindow* aTopWindow, namespace mozilla { -nsresult -RegisterStrongMemoryReporter(nsIMemoryReporter* aReporter) -{ - // Hold a strong reference to the argument to make sure it gets released if - // we return early below. - nsCOMPtr reporter = aReporter; - - nsCOMPtr mgr = - do_GetService("@mozilla.org/memory-reporter-manager;1"); - if (!mgr) { - return NS_ERROR_FAILURE; - } - return mgr->RegisterStrongReporter(reporter); -} - -nsresult -RegisterWeakMemoryReporter(nsIMemoryReporter* aReporter) -{ - nsCOMPtr mgr = - do_GetService("@mozilla.org/memory-reporter-manager;1"); - if (!mgr) { - return NS_ERROR_FAILURE; - } - return mgr->RegisterWeakReporter(aReporter); -} - -nsresult -UnregisterStrongMemoryReporter(nsIMemoryReporter* aReporter) -{ - nsCOMPtr mgr = - do_GetService("@mozilla.org/memory-reporter-manager;1"); - if (!mgr) { - return NS_ERROR_FAILURE; - } - return mgr->UnregisterStrongReporter(aReporter); -} - -nsresult -UnregisterWeakMemoryReporter(nsIMemoryReporter* aReporter) -{ - nsCOMPtr mgr = - do_GetService("@mozilla.org/memory-reporter-manager;1"); - if (!mgr) { - return NS_ERROR_FAILURE; - } - return mgr->UnregisterWeakReporter(aReporter); -} - #define GET_MEMORY_REPORTER_MANAGER(mgr) \ nsRefPtr mgr = \ nsMemoryReporterManager::GetOrCreate(); \ @@ -2358,6 +2327,54 @@ UnregisterWeakMemoryReporter(nsIMemoryReporter* aReporter) return NS_ERROR_FAILURE; \ } +nsresult +RegisterStrongMemoryReporter(nsIMemoryReporter* aReporter) +{ + // Hold a strong reference to the argument to make sure it gets released if + // we return early below. + nsCOMPtr reporter = aReporter; + GET_MEMORY_REPORTER_MANAGER(mgr) + return mgr->RegisterStrongReporter(reporter); +} + +nsresult +RegisterStrongAsyncMemoryReporter(nsIMemoryReporter* aReporter) +{ + // Hold a strong reference to the argument to make sure it gets released if + // we return early below. + nsCOMPtr reporter = aReporter; + GET_MEMORY_REPORTER_MANAGER(mgr) + return mgr->RegisterStrongAsyncReporter(reporter); +} + +nsresult +RegisterWeakMemoryReporter(nsIMemoryReporter* aReporter) +{ + GET_MEMORY_REPORTER_MANAGER(mgr) + return mgr->RegisterWeakReporter(aReporter); +} + +nsresult +RegisterWeakAsyncMemoryReporter(nsIMemoryReporter* aReporter) +{ + GET_MEMORY_REPORTER_MANAGER(mgr) + return mgr->RegisterWeakAsyncReporter(aReporter); +} + +nsresult +UnregisterStrongMemoryReporter(nsIMemoryReporter* aReporter) +{ + GET_MEMORY_REPORTER_MANAGER(mgr) + return mgr->UnregisterStrongReporter(aReporter); +} + +nsresult +UnregisterWeakMemoryReporter(nsIMemoryReporter* aReporter) +{ + GET_MEMORY_REPORTER_MANAGER(mgr) + return mgr->UnregisterWeakReporter(aReporter); +} + // Macro for generating functions that register distinguished amount functions // with the memory reporter manager. #define DEFINE_REGISTER_DISTINGUISHED_AMOUNT(kind, name) \ diff --git a/xpcom/base/nsMemoryReporterManager.h b/xpcom/base/nsMemoryReporterManager.h index 7f17b348a1d6..0e26d4997763 100644 --- a/xpcom/base/nsMemoryReporterManager.h +++ b/xpcom/base/nsMemoryReporterManager.h @@ -41,8 +41,8 @@ public: return static_cast(imgr.get()); } - typedef nsTHashtable> StrongReportersTable; - typedef nsTHashtable> WeakReportersTable; + typedef nsDataHashtable, bool> StrongReportersTable; + typedef nsDataHashtable, bool> WeakReportersTable; // Inter-process memory reporting proceeds as follows. // @@ -184,7 +184,7 @@ public: private: nsresult RegisterReporterHelper(nsIMemoryReporter* aReporter, - bool aForce, bool aStrongRef); + bool aForce, bool aStrongRef, bool aIsAsync); nsresult StartGettingReports(); nsresult FinishReporting(); From f2e4cb7dfeb4fe1de5addd14ddda9f85463279d3 Mon Sep 17 00:00:00 2001 From: Eric Rahm Date: Tue, 6 Oct 2015 11:23:36 -0700 Subject: [PATCH 065/228] Bug 1194555 - Part 6: Run reporters asynchronously. r=njn,jld --- dom/ipc/ContentChild.cpp | 35 +++++++- .../aboutmemory/tests/test_aboutmemory.xul | 9 +- .../aboutmemory/tests/test_aboutmemory2.xul | 9 +- xpcom/base/nsIMemoryReporter.idl | 11 ++- xpcom/base/nsMemoryReporterManager.cpp | 88 +++++++++++++++---- xpcom/base/nsMemoryReporterManager.h | 37 ++++++++ 6 files changed, 166 insertions(+), 23 deletions(-) diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index d3cc35f6d481..da64914f62da 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -895,6 +895,32 @@ NS_IMPL_ISUPPORTS( , nsIMemoryReporterCallback ) +class MemoryReportFinishedCallback final : public nsIFinishReportingCallback +{ +public: + NS_DECL_ISUPPORTS + + explicit MemoryReportFinishedCallback(MemoryReportRequestChild* aActor) + : mActor(aActor) + { + } + + NS_IMETHOD Callback(nsISupports* aUnused) override + { + bool sent = PMemoryReportRequestChild::Send__delete__(mActor); + return sent ? NS_OK : NS_ERROR_FAILURE; + } + +private: + ~MemoryReportFinishedCallback() {} + + nsRefPtr mActor; +}; +NS_IMPL_ISUPPORTS( + MemoryReportFinishedCallback +, nsIFinishReportingCallback +) + bool ContentChild::RecvPMemoryReportRequestConstructor( PMemoryReportRequestChild* aChild, @@ -931,11 +957,12 @@ NS_IMETHODIMP MemoryReportRequestChild::Run() // MemoryReport. nsRefPtr cb = new MemoryReportCallback(this, process); - mgr->GetReportsForThisProcessExtended(cb, nullptr, mAnonymize, - FileDescriptorToFILE(mDMDFile, "wb")); + nsRefPtr finished = + new MemoryReportFinishedCallback(this); - bool sent = Send__delete__(this); - return sent ? NS_OK : NS_ERROR_FAILURE; + return mgr->GetReportsForThisProcessExtended(cb, nullptr, mAnonymize, + FileDescriptorToFILE(mDMDFile, "wb"), + finished, nullptr); } bool diff --git a/toolkit/components/aboutmemory/tests/test_aboutmemory.xul b/toolkit/components/aboutmemory/tests/test_aboutmemory.xul index 8c5a9945dafd..bfeab4c7b415 100644 --- a/toolkit/components/aboutmemory/tests/test_aboutmemory.xul +++ b/toolkit/components/aboutmemory/tests/test_aboutmemory.xul @@ -552,7 +552,14 @@ End of 5th\n\ SimpleTest.waitForClipboard( function(aActual) { mostRecentActual = aActual; - return aActual.trim() === aExpected.trim(); + let rslt = aActual.trim() === aExpected.trim(); + if (!rslt) { + // Try copying again. + synthesizeKey("A", {accelKey: true}); + synthesizeKey("C", {accelKey: true}); + } + + return rslt; }, function() { synthesizeKey("A", {accelKey: true}); diff --git a/toolkit/components/aboutmemory/tests/test_aboutmemory2.xul b/toolkit/components/aboutmemory/tests/test_aboutmemory2.xul index e2f93d0adc4a..8cf197e6d114 100644 --- a/toolkit/components/aboutmemory/tests/test_aboutmemory2.xul +++ b/toolkit/components/aboutmemory/tests/test_aboutmemory2.xul @@ -106,7 +106,14 @@ SimpleTest.waitForClipboard( function(aActual) { mostRecentActual = aActual; - return aActual.trim() === aExpected.trim(); + let rslt = aActual.trim() === aExpected.trim(); + if (!rslt) { + // Try copying again. + synthesizeKey("A", {accelKey: true}); + synthesizeKey("C", {accelKey: true}); + } + + return rslt; }, function() { synthesizeKey("A", {accelKey: true}); diff --git a/xpcom/base/nsIMemoryReporter.idl b/xpcom/base/nsIMemoryReporter.idl index bcfb4e3acc66..e00f736f55c9 100644 --- a/xpcom/base/nsIMemoryReporter.idl +++ b/xpcom/base/nsIMemoryReporter.idl @@ -205,7 +205,7 @@ interface nsIFinishReportingCallback : nsISupports void callback(in nsISupports data); }; -[scriptable, builtinclass, uuid(babbadb0-b22d-4b05-9ca9-01e617828ec1)] +[scriptable, builtinclass, uuid(61de6dc7-ed11-4104-a577-79941f22f434)] interface nsIMemoryReporterManager : nsISupports { /* @@ -299,7 +299,14 @@ interface nsIMemoryReporterManager : nsISupports getReportsForThisProcessExtended(in nsIMemoryReporterCallback handleReport, in nsISupports handleReportData, in boolean anonymize, - in FILE DMDFile); + in FILE DMDFile, + in nsIFinishReportingCallback finishReporting, + in nsISupports finishReportingData); + + /* + * Called by an asynchronous memory reporter upon completion. + */ + [noscript] void endReport(); /* * The memory reporter manager, for the most part, treats reporters diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp index 21582ff43a1b..eef9f403a595 100644 --- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -1357,6 +1357,7 @@ nsMemoryReporterManager::nsMemoryReporterManager() , mSavedWeakReporters(nullptr) , mNextGeneration(1) , mPendingProcessesState(nullptr) + , mPendingReportersState(nullptr) { } @@ -1466,8 +1467,11 @@ nsMemoryReporterManager::StartGettingReports() } } #endif + + // This is async. GetReportsForThisProcessExtended(s->mHandleReport, s->mHandleReportData, - s->mAnonymize, parentDMDFile); + s->mAnonymize, parentDMDFile, + s->mFinishReporting, s->mFinishReportingData); nsTArray childWeakRefs; ContentParent::GetAll(childWeakRefs); @@ -1499,16 +1503,44 @@ nsMemoryReporterManager::StartGettingReports() s->mTimer.swap(timer); } - // The parent's report is done; make note of that, and start - // launching child process reports (if any). - EndProcessReport(s->mGeneration, true); return NS_OK; } +void +nsMemoryReporterManager::DispatchReporter( + nsIMemoryReporter* aReporter, bool aIsAsync, + nsIHandleReportCallback* aHandleReport, + nsISupports* aHandleReportData, + bool aAnonymize) +{ + MOZ_ASSERT(mPendingReportersState); + + // Grab refs to everything used in the lambda function. + nsRefPtr self = this; + nsCOMPtr reporter = aReporter; + nsCOMPtr handleReport = aHandleReport; + nsCOMPtr handleReportData = aHandleReportData; + + nsCOMPtr event = NS_NewRunnableFunction( + [self, reporter, aIsAsync, handleReport, handleReportData, aAnonymize] () { + reporter->CollectReports(handleReport, + handleReportData, + aAnonymize); + if (!aIsAsync) { + self->EndReport(); + } + }); + + NS_DispatchToMainThread(event); + mPendingReportersState->mReportsPending++; +} + NS_IMETHODIMP nsMemoryReporterManager::GetReportsForThisProcessExtended( nsIHandleReportCallback* aHandleReport, nsISupports* aHandleReportData, - bool aAnonymize, FILE* aDMDFile) + bool aAnonymize, FILE* aDMDFile, + nsIFinishReportingCallback* aFinishReporting, + nsISupports* aFinishReportingData) { // Memory reporters are not necessarily threadsafe, so this function must // be called from the main thread. @@ -1516,6 +1548,11 @@ nsMemoryReporterManager::GetReportsForThisProcessExtended( MOZ_CRASH(); } + if (NS_WARN_IF(mPendingReportersState)) { + // Report is already in progress. + return NS_ERROR_IN_PROGRESS; + } + #ifdef MOZ_DMD if (aDMDFile) { // Clear DMD's reportedness state before running the memory @@ -1526,26 +1563,47 @@ nsMemoryReporterManager::GetReportsForThisProcessExtended( MOZ_ASSERT(!aDMDFile); #endif - nsCOMArray allReporters; + mPendingReportersState = new PendingReportersState( + aFinishReporting, aFinishReportingData, aDMDFile); + { mozilla::MutexAutoLock autoLock(mMutex); + for (auto iter = mStrongReporters->Iter(); !iter.Done(); iter.Next()) { - allReporters.AppendElement(iter.Key()); + DispatchReporter(iter.Key(), iter.Data(), + aHandleReport, aHandleReportData, aAnonymize); } + for (auto iter = mWeakReporters->Iter(); !iter.Done(); iter.Next()) { - allReporters.AppendElement(iter.Key()); + nsCOMPtr reporter = iter.Key(); + DispatchReporter(reporter, iter.Data(), + aHandleReport, aHandleReportData, aAnonymize); } } - for (uint32_t i = 0; i < allReporters.Length(); i++) { - allReporters[i]->CollectReports(aHandleReport, aHandleReportData, - aAnonymize); - } + return NS_OK; +} + +NS_IMETHODIMP +nsMemoryReporterManager::EndReport() +{ + if (--mPendingReportersState->mReportsPending == 0) { #ifdef MOZ_DMD - if (aDMDFile) { - return nsMemoryInfoDumper::DumpDMDToFile(aDMDFile); - } + if (mPendingReportersState->mDMDFile) { + nsMemoryInfoDumper::DumpDMDToFile(mPendingReportersState->mDMDFile); + } #endif + if (mPendingProcessesState) { + // This is the parent process. + EndProcessReport(mPendingProcessesState->mGeneration, true); + } else { + mPendingReportersState->mFinishReporting->Callback( + mPendingReportersState->mFinishReportingData); + } + + delete mPendingReportersState; + mPendingReportersState = nullptr; + } return NS_OK; } diff --git a/xpcom/base/nsMemoryReporterManager.h b/xpcom/base/nsMemoryReporterManager.h index 0e26d4997763..16af7b53f240 100644 --- a/xpcom/base/nsMemoryReporterManager.h +++ b/xpcom/base/nsMemoryReporterManager.h @@ -188,6 +188,11 @@ private: nsresult StartGettingReports(); nsresult FinishReporting(); + void DispatchReporter(nsIMemoryReporter* aReporter, bool aIsAsync, + nsIHandleReportCallback* aHandleReport, + nsISupports* aHandleReportData, + bool aAnonymize); + static void TimeoutCallback(nsITimer* aTimer, void* aData); // Note: this timeout needs to be long enough to allow for the // possibility of DMD reports and/or running on a low-end phone. @@ -205,6 +210,9 @@ private: uint32_t mNextGeneration; + // Used to keep track of state of which processes are currently running and + // waiting to run memory reports. Holds references to parameters needed when + // requesting a memory report and finishing reporting. struct PendingProcessesState { uint32_t mGeneration; @@ -230,11 +238,40 @@ private: const nsAString& aDMDDumpIdent); }; + // Used to keep track of the state of the asynchronously run memory + // reporters. The callback and file handle used when all memory reporters + // have finished are also stored here. + struct PendingReportersState + { + // Number of memory reporters currently running. + uint32_t mReportsPending; + + // Callback for when all memory reporters have completed. + nsCOMPtr mFinishReporting; + nsCOMPtr mFinishReportingData; + + // File handle to write a DMD report to if requested. + FILE* mDMDFile; + + PendingReportersState(nsIFinishReportingCallback* aFinishReporting, + nsISupports* aFinishReportingData, + FILE* aDMDFile) + : mReportsPending(0) + , mFinishReporting(aFinishReporting) + , mFinishReportingData(aFinishReportingData) + , mDMDFile(aDMDFile) + { + } + }; + // When this is non-null, a request is in flight. Note: We use manual // new/delete for this because its lifetime doesn't match block scope or // anything like that. PendingProcessesState* mPendingProcessesState; + // This is reinitialized each time a call to GetReports is initiated. + PendingReportersState* mPendingReportersState; + PendingProcessesState* GetStateForGeneration(uint32_t aGeneration); static bool StartChildReport(mozilla::dom::ContentParent* aChild, const PendingProcessesState* aState); From d5a9ab2740b5f5ea521ef6c1cec89057aade91b0 Mon Sep 17 00:00:00 2001 From: Joel Maher Date: Tue, 6 Oct 2015 15:19:28 -0400 Subject: [PATCH 066/228] Bug 1211889 - [mozharness] prepare to split mochitest-chrome into chunks (c1, c2, c3). r=armenzg --- testing/mozharness/configs/unittests/linux_unittest.py | 1 + testing/mozharness/configs/unittests/mac_unittest.py | 1 + testing/mozharness/configs/unittests/win_unittest.py | 1 + 3 files changed, 3 insertions(+) diff --git a/testing/mozharness/configs/unittests/linux_unittest.py b/testing/mozharness/configs/unittests/linux_unittest.py index 2b1c5f357fcb..d4b75787cbdc 100644 --- a/testing/mozharness/configs/unittests/linux_unittest.py +++ b/testing/mozharness/configs/unittests/linux_unittest.py @@ -183,6 +183,7 @@ config = { "plain-chunked": ["--chunk-by-dir=4"], "mochitest-push": ["--subsuite=push"], "chrome": ["--chrome"], + "chrome-chunked": ["--chrome", "--chunk-by-dir=4"], "browser-chrome": ["--browser-chrome"], "browser-chrome-chunked": ["--browser-chrome", "--chunk-by-runtime"], "browser-chrome-addons": ["--browser-chrome", "--chunk-by-runtime", "--tag=addons"], diff --git a/testing/mozharness/configs/unittests/mac_unittest.py b/testing/mozharness/configs/unittests/mac_unittest.py index b1adf1619176..5e8aac88fb87 100644 --- a/testing/mozharness/configs/unittests/mac_unittest.py +++ b/testing/mozharness/configs/unittests/mac_unittest.py @@ -150,6 +150,7 @@ config = { "plain-chunked": ["--chunk-by-dir=4"], "mochitest-push": ["--subsuite=push"], "chrome": ["--chrome"], + "chrome-chunked": ["--chrome", "--chunk-by-dir=4"], "browser-chrome": ["--browser-chrome"], "browser-chrome-chunked": ["--browser-chrome", "--chunk-by-runtime"], "browser-chrome-addons": ["--browser-chrome", "--chunk-by-runtime", "--tag=addons"], diff --git a/testing/mozharness/configs/unittests/win_unittest.py b/testing/mozharness/configs/unittests/win_unittest.py index 315d02beb5fb..e58559b138af 100644 --- a/testing/mozharness/configs/unittests/win_unittest.py +++ b/testing/mozharness/configs/unittests/win_unittest.py @@ -159,6 +159,7 @@ config = { "plain-chunked": ["--chunk-by-dir=4"], "mochitest-push": ["--subsuite=push"], "chrome": ["--chrome"], + "chrome-chunked": ["--chrome", "--chunk-by-dir=4"], "browser-chrome": ["--browser-chrome"], "browser-chrome-chunked": ["--browser-chrome", "--chunk-by-runtime"], "browser-chrome-addons": ["--browser-chrome", "--chunk-by-runtime", "--tag=addons"], From ef553da5424f6fccb48eb4fb43c2b088a90d6687 Mon Sep 17 00:00:00 2001 From: Jim Mathies Date: Tue, 6 Oct 2015 14:23:24 -0500 Subject: [PATCH 067/228] Bug 1196539 - Apply plugin config using AutoResolveRefLayers during composition. r=matt.woodrow --- gfx/layers/Layers.cpp | 4 + .../composite/AsyncCompositionManager.cpp | 27 ++++-- .../composite/AsyncCompositionManager.h | 14 ++- gfx/layers/ipc/CompositorParent.cpp | 93 +++++++------------ gfx/layers/ipc/CompositorParent.h | 8 ++ 5 files changed, 80 insertions(+), 66 deletions(-) diff --git a/gfx/layers/Layers.cpp b/gfx/layers/Layers.cpp index 2aac575dc01e..53485015b3f7 100644 --- a/gfx/layers/Layers.cpp +++ b/gfx/layers/Layers.cpp @@ -993,6 +993,10 @@ Layer::GetVisibleRegionRelativeToRootLayer(nsIntRegion& aResult, { MOZ_ASSERT(aLayerOffset, "invalid offset pointer"); + if (!GetParent()) { + return false; + } + IntPoint offset; aResult = GetEffectiveVisibleRegion(); for (Layer* layer = this; layer; layer = layer->GetParent()) { diff --git a/gfx/layers/composite/AsyncCompositionManager.cpp b/gfx/layers/composite/AsyncCompositionManager.cpp index 7276641b0d61..51e8fb4e73a4 100644 --- a/gfx/layers/composite/AsyncCompositionManager.cpp +++ b/gfx/layers/composite/AsyncCompositionManager.cpp @@ -68,9 +68,12 @@ template static void WalkTheTree(Layer* aLayer, bool& aReady, - const TargetConfig& aTargetConfig) + bool &aHasRemote, + const TargetConfig& aTargetConfig, + bool aResolvePlugins) { if (RefLayer* ref = aLayer->AsRefLayer()) { + aHasRemote = true; if (const CompositorParent::LayerTreeState* state = CompositorParent::GetIndirectShadowTree(ref->GetReferentId())) { if (Layer* referent = state->mRoot) { if (!ref->GetVisibleRegion().IsEmpty()) { @@ -84,16 +87,21 @@ WalkTheTree(Layer* aLayer, if (OP == Resolve) { ref->ConnectReferentLayer(referent); +#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) + if (aResolvePlugins) { + CompositorParent::UpdatePluginWindowState(ref->GetReferentId()); + } +#endif } else { ref->DetachReferentLayer(referent); - WalkTheTree(referent, aReady, aTargetConfig); + WalkTheTree(referent, aReady, aHasRemote, aTargetConfig, aResolvePlugins); } } } } for (Layer* child = aLayer->GetFirstChild(); child; child = child->GetNextSibling()) { - WalkTheTree(child, aReady, aTargetConfig); + WalkTheTree(child, aReady, aHasRemote, aTargetConfig, aResolvePlugins); } } @@ -103,6 +111,7 @@ AsyncCompositionManager::AsyncCompositionManager(LayerManagerComposite* aManager , mLayersUpdated(false) , mPaintSyncId(0) , mReadyForCompose(true) + , mHasRemoteContent(false) { } @@ -111,16 +120,19 @@ AsyncCompositionManager::~AsyncCompositionManager() } void -AsyncCompositionManager::ResolveRefLayers() +AsyncCompositionManager::ResolveRefLayers(bool aResolvePlugins) { if (!mLayerManager->GetRoot()) { return; } mReadyForCompose = true; + mHasRemoteContent = false; WalkTheTree(mLayerManager->GetRoot(), mReadyForCompose, - mTargetConfig); + mHasRemoteContent, + mTargetConfig, + aResolvePlugins); } void @@ -129,9 +141,12 @@ AsyncCompositionManager::DetachRefLayers() if (!mLayerManager->GetRoot()) { return; } + bool ignored = false; WalkTheTree(mLayerManager->GetRoot(), mReadyForCompose, - mTargetConfig); + ignored, + mTargetConfig, + ignored); } void diff --git a/gfx/layers/composite/AsyncCompositionManager.h b/gfx/layers/composite/AsyncCompositionManager.h index 4432b125bd3e..a41f36add210 100644 --- a/gfx/layers/composite/AsyncCompositionManager.h +++ b/gfx/layers/composite/AsyncCompositionManager.h @@ -117,6 +117,10 @@ public: // True if the underlying layer tree is ready to be composited. bool ReadyForCompose() { return mReadyForCompose; } + // Indicates if during the last composition remote content was detected. + // Updated in CompositorParent's CompositeToTarget. + bool HasRemoteContent() { return mHasRemoteContent; } + // Returns true if the next composition will be the first for a // particular document. bool IsFirstPaint() { return mIsFirstPaint; } @@ -186,7 +190,8 @@ private: * For reach RefLayer in our layer tree, look up its referent and connect it * to the layer tree, if found. */ - void ResolveRefLayers(); + void ResolveRefLayers(bool aResolvePlugins); + /** * Detaches all referents resolved by ResolveRefLayers. * Assumes that mLayerManager->GetRoot() and mTargetConfig have not changed @@ -215,6 +220,7 @@ private: int32_t mPaintSyncId; bool mReadyForCompose; + bool mHasRemoteContent; gfx::Matrix mWorldTransform; LayerTransformRecorder mLayerTransformRecorder; @@ -224,10 +230,12 @@ MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(AsyncCompositionManager::TransformsToSkip) class MOZ_STACK_CLASS AutoResolveRefLayers { public: - explicit AutoResolveRefLayers(AsyncCompositionManager* aManager) : mManager(aManager) + explicit AutoResolveRefLayers(AsyncCompositionManager* aManager, + bool aResolvePlugins = false) : + mManager(aManager) { if (mManager) { - mManager->ResolveRefLayers(); + mManager->ResolveRefLayers(aResolvePlugins); } } diff --git a/gfx/layers/ipc/CompositorParent.cpp b/gfx/layers/ipc/CompositorParent.cpp index 5e0b3fbaccb2..9b6d3393507b 100644 --- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -1040,7 +1040,15 @@ CompositorParent::CompositeToTarget(DrawTarget* aTarget, const gfx::IntRect* aRe return; } - AutoResolveRefLayers resolve(mCompositionManager); + AutoResolveRefLayers resolve(mCompositionManager, true); + +#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) + // We do not support plugins in local content. When switching tabs + // to local pages, hide every plugin associated with the window. + if (!mCompositionManager->HasRemoteContent()) { + unused << SendHideAllPlugins((uintptr_t)GetWidget()); + } +#endif if (aTarget) { mLayerManager->BeginTransactionWithDrawTarget(aTarget, *aRect); @@ -1998,67 +2006,41 @@ CrossProcessCompositorParent::ShadowLayersUpdated( } #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) -// Sends plugin window state changes to the main thread -static void -UpdatePluginWindowState(uint64_t aId) +// static, sends plugin window state changes to the main thread +void +CompositorParent::UpdatePluginWindowState(uint64_t aId) { CompositorParent::LayerTreeState& lts = sIndirectLayerTrees[aId]; - if (!lts.mPluginData.Length() && !lts.mUpdatedPluginDataAvailable) { + if (!lts.mUpdatedPluginDataAvailable) { return; } - bool shouldComposePlugin = !!lts.mRoot && - !!lts.mRoot->GetParent(); - - bool shouldHidePlugin = !lts.mRoot || - !lts.mRoot->GetParent(); - - if (shouldComposePlugin) { - if (!lts.mPluginData.Length()) { - // We will pass through here in cases where the previous shadow layer - // tree contained visible plugins and the new tree does not. All we need - // to do here is hide the plugins for the old tree, so don't waste time - // calculating clipping. - uintptr_t parentWidget = (uintptr_t)lts.mParent->GetWidget(); - unused << lts.mParent->SendHideAllPlugins(parentWidget); - lts.mUpdatedPluginDataAvailable = false; - return; - } - - // Retrieve the offset and visible region of the layer that hosts - // the plugins, CompositorChild needs these in calculating proper - // plugin clipping. - LayerTransactionParent* layerTree = lts.mLayerTree; - Layer* contentRoot = layerTree->GetRoot(); - if (contentRoot) { - nsIntPoint offset; - nsIntRegion visibleRegion; - if (contentRoot->GetVisibleRegionRelativeToRootLayer(visibleRegion, - &offset)) { - unused << - lts.mParent->SendUpdatePluginConfigurations(offset, visibleRegion, - lts.mPluginData); - lts.mUpdatedPluginDataAvailable = false; - } else { - shouldHidePlugin = true; - } - } + if (!lts.mPluginData.Length()) { + // We will pass through here in cases where the previous shadow layer + // tree contained visible plugins and the new tree does not. All we need + // to do here is hide the plugins for the old tree, so don't waste time + // calculating clipping. + uintptr_t parentWidget = (uintptr_t)lts.mParent->GetWidget(); + unused << lts.mParent->SendHideAllPlugins(parentWidget); + lts.mUpdatedPluginDataAvailable = false; + return; } - // Hide all of our plugins, this remote layer tree is no longer active. - if (shouldHidePlugin) { - for (uint32_t pluginsIdx = 0; pluginsIdx < lts.mPluginData.Length(); - pluginsIdx++) { - lts.mPluginData[pluginsIdx].visible() = false; - } + // Retrieve the offset and visible region of the layer that hosts + // the plugins, CompositorChild needs these in calculating proper + // plugin clipping. + LayerTransactionParent* layerTree = lts.mLayerTree; + Layer* contentRoot = layerTree->GetRoot(); + if (contentRoot) { nsIntPoint offset; - nsIntRegion region; - unused << lts.mParent->SendUpdatePluginConfigurations(offset, - region, - lts.mPluginData); - // Clear because there's no recovering from this until we receive - // new shadow layer plugin data in ShadowLayersUpdated. - lts.mPluginData.Clear(); + nsIntRegion visibleRegion; + if (contentRoot->GetVisibleRegionRelativeToRootLayer(visibleRegion, + &offset)) { + unused << + lts.mParent->SendUpdatePluginConfigurations(offset, visibleRegion, + lts.mPluginData); + lts.mUpdatedPluginDataAvailable = false; + } } } #endif // #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) @@ -2074,9 +2056,6 @@ CrossProcessCompositorParent::DidComposite(uint64_t aId, unused << SendDidComposite(aId, layerTree->GetPendingTransactionId(), aCompositeStart, aCompositeEnd); layerTree->SetPendingTransactionId(0); } -#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) - UpdatePluginWindowState(aId); -#endif } void diff --git a/gfx/layers/ipc/CompositorParent.h b/gfx/layers/ipc/CompositorParent.h index 8c0e429e8a74..762821e839c4 100644 --- a/gfx/layers/ipc/CompositorParent.h +++ b/gfx/layers/ipc/CompositorParent.h @@ -381,6 +381,14 @@ public: */ static LayerTreeState* GetIndirectShadowTree(uint64_t aId); +#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) + /** + * Calculates and updates plugin positioning and clip via ipc messages + * sent to the main thread. + */ + static void UpdatePluginWindowState(uint64_t aId); +#endif + /** * Used by the profiler to denote when a vsync occured */ From f70b45c5504ef65a94d7fd5454242d9e92293765 Mon Sep 17 00:00:00 2001 From: Jim Mathies Date: Tue, 6 Oct 2015 14:23:24 -0500 Subject: [PATCH 068/228] Bug 1196539 - Add plugin window visibility tests. r=roc --- dom/plugins/test/mochitest/browser.ini | 2 + .../test/mochitest/browser_bug1196539.js | 159 ++++++++++++++++++ dom/plugins/test/testplugin/nptest.cpp | 15 ++ 3 files changed, 176 insertions(+) create mode 100644 dom/plugins/test/mochitest/browser_bug1196539.js diff --git a/dom/plugins/test/mochitest/browser.ini b/dom/plugins/test/mochitest/browser.ini index 39e3da6db8ef..a0dc6d4807d0 100644 --- a/dom/plugins/test/mochitest/browser.ini +++ b/dom/plugins/test/mochitest/browser.ini @@ -4,3 +4,5 @@ support-files = [browser_bug1163570.js] skip-if = (!e10s || os != "win") +[browser_bug1196539.js] +skip-if = (!e10s || os != "win") diff --git a/dom/plugins/test/mochitest/browser_bug1196539.js b/dom/plugins/test/mochitest/browser_bug1196539.js new file mode 100644 index 000000000000..874bdd19f922 --- /dev/null +++ b/dom/plugins/test/mochitest/browser_bug1196539.js @@ -0,0 +1,159 @@ +let gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/"); + +// Returns the chrome side nsIPluginTag for this plugin +function getTestPlugin(aName) { + let pluginName = aName || "Test Plug-in"; + let ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost); + let tags = ph.getPluginTags(); + + // Find the test plugin + for (let i = 0; i < tags.length; i++) { + if (tags[i].name == pluginName) + return tags[i]; + } + ok(false, "Unable to find plugin"); + return null; +} + +// Set the test plugin state, disabling features like click-to-play +function setTestPluginEnabledState(newEnabledState, pluginName) { + let name = pluginName || "Test Plug-in"; + let plugin = getTestPlugin(name); + plugin.enabledState = newEnabledState; +} + +function promiseNewTabSwitched() { + return new Promise(resolve => { + gBrowser.addEventListener("TabSwitchDone", function onSwitch() { + gBrowser.removeEventListener("TabSwitchDone", onSwitch); + executeSoon(resolve); + }); + }); +} + +function waitForMs(aMs) { + return new Promise((resolve) => { + setTimeout(done, aMs); + function done() { + resolve(true); + } + }); +} + +function checkPaintCount(aCount) { + ok(aCount != 0, "paint count can't be greater than zero, count was " + aCount); + ok(aCount < kMaxPaints, "paint count should be within limits, count was " + aCount); +} + +// maximum number of paints we allow before failing. The test plugin doesn't +// animate so this should really be just 1, but operating systems can +// occasionally fire a few of these so we give these tests a fudge factor. +// A bad regression would either be 0, or 100+. +const kMaxPaints = 10; + +add_task(function* () { + let result, tabSwitchedPromise; + + setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in"); + + let testTab = gBrowser.selectedTab; + let pluginTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, gTestRoot + "plugin_test.html"); + let homeTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:home"); + + result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + return !!plugin; + }); + is(result, true, "plugin is loaded"); + + result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + return !XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible(); + }); + is(result, true, "plugin is hidden"); + + // reset plugin paint count + yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + XPCNativeWrapper.unwrap(plugin).resetPaintCount(); + }); + + // select plugin tab + tabSwitchedPromise = promiseNewTabSwitched(); + gBrowser.selectedTab = pluginTab; + yield tabSwitchedPromise; + + // wait a bit for spurious paints + yield waitForMs(100); + + result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible(); + }); + is(result, true, "plugin is visible"); + + // check for good paint count + result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + return XPCNativeWrapper.unwrap(plugin).getPaintCount(); + }); + checkPaintCount(result); + + // select home tab + tabSwitchedPromise = promiseNewTabSwitched(); + gBrowser.selectedTab = homeTab; + yield tabSwitchedPromise; + + // reset paint count + yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + XPCNativeWrapper.unwrap(plugin).resetPaintCount(); + }); + + // wait a bit for spurious paints + yield waitForMs(100); + + // check for no paint count + result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + return XPCNativeWrapper.unwrap(plugin).getPaintCount(); + }); + is(result, 0, "no paints, this is correct."); + + result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + return !XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible(); + }); + is(result, true, "plugin is hidden"); + + // reset paint count + yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + XPCNativeWrapper.unwrap(plugin).resetPaintCount(); + }); + + // select plugin tab + tabSwitchedPromise = promiseNewTabSwitched(); + gBrowser.selectedTab = pluginTab; + yield tabSwitchedPromise; + + // check paint count + result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + return XPCNativeWrapper.unwrap(plugin).getPaintCount(); + }); + checkPaintCount(result); + + gBrowser.removeTab(homeTab); + gBrowser.removeTab(pluginTab); +}); diff --git a/dom/plugins/test/testplugin/nptest.cpp b/dom/plugins/test/testplugin/nptest.cpp index 4d21a16fb904..16be70e506f6 100644 --- a/dom/plugins/test/testplugin/nptest.cpp +++ b/dom/plugins/test/testplugin/nptest.cpp @@ -122,6 +122,7 @@ static bool stopWatchingInstanceCount(NPObject* npobj, const NPVariant* args, ui static bool getLastMouseX(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result); static bool getLastMouseY(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result); static bool getPaintCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result); +static bool resetPaintCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result); static bool getWidthAtLastPaint(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result); static bool setInvalidateDuringPaint(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result); static bool setSlowPaint(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result); @@ -192,6 +193,7 @@ static const NPUTF8* sPluginMethodIdentifierNames[] = { "getLastMouseX", "getLastMouseY", "getPaintCount", + "resetPaintCount", "getWidthAtLastPaint", "setInvalidateDuringPaint", "setSlowPaint", @@ -263,6 +265,7 @@ static const ScriptableFunction sPluginMethodFunctions[] = { getLastMouseX, getLastMouseY, getPaintCount, + resetPaintCount, getWidthAtLastPaint, setInvalidateDuringPaint, setSlowPaint, @@ -2436,6 +2439,18 @@ getPaintCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVaria return true; } +static bool +resetPaintCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount != 0) + return false; + + NPP npp = static_cast(npobj)->npp; + InstanceData* id = static_cast(npp->pdata); + id->paintCount = 0; + return true; +} + static bool getWidthAtLastPaint(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result) { From 36f1f86bc4d06ddddab1ff4986584566875cf974 Mon Sep 17 00:00:00 2001 From: Jim Mathies Date: Tue, 6 Oct 2015 14:23:24 -0500 Subject: [PATCH 069/228] Bug 1137944 - Cache compositor plugin update data to avoid sending updates to the main thread when the data doesn't change. r=roc --- gfx/layers/ipc/CompositorParent.cpp | 96 +++++++++++++++++++++++------ gfx/layers/ipc/CompositorParent.h | 14 ++++- 2 files changed, 87 insertions(+), 23 deletions(-) diff --git a/gfx/layers/ipc/CompositorParent.cpp b/gfx/layers/ipc/CompositorParent.cpp index 9b6d3393507b..57b309079385 100644 --- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -551,6 +551,9 @@ CompositorParent::CompositorParent(nsIWidget* aWidget, , mForceCompositionTask(nullptr) , mCompositorThreadHolder(sCompositorThreadHolder) , mCompositorScheduler(nullptr) +#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) + , mLastPluginUpdateLayerTreeId(0) +#endif { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(CompositorThread(), @@ -2006,13 +2009,49 @@ CrossProcessCompositorParent::ShadowLayersUpdated( } #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) -// static, sends plugin window state changes to the main thread -void +//#define PLUGINS_LOG(...) printf_stderr("CP [%s]: ", __FUNCTION__); +// printf_stderr(__VA_ARGS__); +// printf_stderr("\n"); +#define PLUGINS_LOG(...) + +bool CompositorParent::UpdatePluginWindowState(uint64_t aId) { CompositorParent::LayerTreeState& lts = sIndirectLayerTrees[aId]; + // Check if this layer tree has received any shadow layer updates if (!lts.mUpdatedPluginDataAvailable) { - return; + PLUGINS_LOG("[%" PRIu64 "] no plugin data", aId); + return false; + } + + // pluginMetricsChanged tracks whether we need to send plugin update + // data to the main thread. If we do we'll have to block composition, + // which we want to avoid if at all possible. + bool pluginMetricsChanged = false; + + // Same layer tree checks + if (mLastPluginUpdateLayerTreeId == aId) { + // no plugin data and nothing has changed, bail. + if (!mCachedPluginData.Length() && !lts.mPluginData.Length()) { + PLUGINS_LOG("[%" PRIu64 "] no data, no changes", aId); + return false; + } + + if (mCachedPluginData.Length() == lts.mPluginData.Length()) { + // check for plugin data changes + for (uint32_t idx = 0; idx < lts.mPluginData.Length(); idx++) { + if (!(mCachedPluginData[idx] == lts.mPluginData[idx])) { + pluginMetricsChanged = true; + break; + } + } + } else { + // array lengths don't match, need to update + pluginMetricsChanged = true; + } + } else { + // exchanging layer trees, we need to update + pluginMetricsChanged = true; } if (!lts.mPluginData.Length()) { @@ -2020,28 +2059,45 @@ CompositorParent::UpdatePluginWindowState(uint64_t aId) // tree contained visible plugins and the new tree does not. All we need // to do here is hide the plugins for the old tree, so don't waste time // calculating clipping. + mPluginsLayerOffset = nsIntPoint(0,0); + mPluginsLayerVisibleRegion.SetEmpty(); uintptr_t parentWidget = (uintptr_t)lts.mParent->GetWidget(); unused << lts.mParent->SendHideAllPlugins(parentWidget); lts.mUpdatedPluginDataAvailable = false; - return; - } - - // Retrieve the offset and visible region of the layer that hosts - // the plugins, CompositorChild needs these in calculating proper - // plugin clipping. - LayerTransactionParent* layerTree = lts.mLayerTree; - Layer* contentRoot = layerTree->GetRoot(); - if (contentRoot) { - nsIntPoint offset; - nsIntRegion visibleRegion; - if (contentRoot->GetVisibleRegionRelativeToRootLayer(visibleRegion, - &offset)) { - unused << - lts.mParent->SendUpdatePluginConfigurations(offset, visibleRegion, - lts.mPluginData); - lts.mUpdatedPluginDataAvailable = false; + PLUGINS_LOG("[%" PRIu64 "] hide all", aId); + } else { + // Retrieve the offset and visible region of the layer that hosts + // the plugins, CompositorChild needs these in calculating proper + // plugin clipping. + LayerTransactionParent* layerTree = lts.mLayerTree; + Layer* contentRoot = layerTree->GetRoot(); + if (contentRoot) { + nsIntPoint offset; + nsIntRegion visibleRegion; + if (contentRoot->GetVisibleRegionRelativeToRootLayer(visibleRegion, + &offset)) { + // Check to see if these values have changed, if so we need to + // update plugin window position within the window. + if (!pluginMetricsChanged && + mPluginsLayerVisibleRegion == visibleRegion && + mPluginsLayerOffset == offset) { + PLUGINS_LOG("[%" PRIu64 "] no change", aId); + return false; + } + mPluginsLayerOffset = offset; + mPluginsLayerVisibleRegion = visibleRegion; + unused << + lts.mParent->SendUpdatePluginConfigurations(offset, visibleRegion, + lts.mPluginData); + lts.mUpdatedPluginDataAvailable = false; + PLUGINS_LOG("[%" PRIu64 "] updated", aId); + } } } + + mLastPluginUpdateLayerTreeId = aId; + mCachedPluginData = lts.mPluginData; + return true; } #endif // #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) diff --git a/gfx/layers/ipc/CompositorParent.h b/gfx/layers/ipc/CompositorParent.h index 762821e839c4..711fd3d69437 100644 --- a/gfx/layers/ipc/CompositorParent.h +++ b/gfx/layers/ipc/CompositorParent.h @@ -383,10 +383,10 @@ public: #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) /** - * Calculates and updates plugin positioning and clip via ipc messages - * sent to the main thread. + * Calculates and requests the main thread update plugin positioning, clip, + * and visibility via ipc. */ - static void UpdatePluginWindowState(uint64_t aId); + void UpdatePluginWindowState(uint64_t aId); #endif /** @@ -478,6 +478,14 @@ protected: nsRefPtr mCompositorThreadHolder; nsRefPtr mCompositorScheduler; +#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) + // cached plugin data used to reduce the number of updates we request. + uint64_t mLastPluginUpdateLayerTreeId; + nsIntPoint mPluginsLayerOffset; + nsIntRegion mPluginsLayerVisibleRegion; + nsTArray mCachedPluginData; +#endif + DISALLOW_EVIL_CONSTRUCTORS(CompositorParent); }; From 4f6da4f6c9a7b2508d47dce21e01a55eebc91ce1 Mon Sep 17 00:00:00 2001 From: Jim Mathies Date: Tue, 6 Oct 2015 14:23:24 -0500 Subject: [PATCH 070/228] Bug 1137944 - Move plugin window metrics updates to a point during comososition where we know the remote layer tree is hooked up to the chrome layer tree. r=matt.woodrow --- .../composite/AsyncCompositionManager.cpp | 49 ++++++++++++++----- .../composite/AsyncCompositionManager.h | 21 +++++--- 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/gfx/layers/composite/AsyncCompositionManager.cpp b/gfx/layers/composite/AsyncCompositionManager.cpp index 51e8fb4e73a4..96f1834d69eb 100644 --- a/gfx/layers/composite/AsyncCompositionManager.cpp +++ b/gfx/layers/composite/AsyncCompositionManager.cpp @@ -68,9 +68,11 @@ template static void WalkTheTree(Layer* aLayer, bool& aReady, - bool &aHasRemote, const TargetConfig& aTargetConfig, - bool aResolvePlugins) + CompositorParent* aCompositor, + bool& aHasRemote, + bool aWillResolvePlugins, + bool& aDidResolvePlugins) { if (RefLayer* ref = aLayer->AsRefLayer()) { aHasRemote = true; @@ -88,20 +90,25 @@ WalkTheTree(Layer* aLayer, if (OP == Resolve) { ref->ConnectReferentLayer(referent); #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) - if (aResolvePlugins) { - CompositorParent::UpdatePluginWindowState(ref->GetReferentId()); + if (aCompositor && aWillResolvePlugins) { + aDidResolvePlugins |= + aCompositor->UpdatePluginWindowState(ref->GetReferentId()); } #endif } else { ref->DetachReferentLayer(referent); - WalkTheTree(referent, aReady, aHasRemote, aTargetConfig, aResolvePlugins); + WalkTheTree(referent, aReady, aTargetConfig, + aCompositor, aHasRemote, aWillResolvePlugins, + aDidResolvePlugins); } } } } for (Layer* child = aLayer->GetFirstChild(); child; child = child->GetNextSibling()) { - WalkTheTree(child, aReady, aHasRemote, aTargetConfig, aResolvePlugins); + WalkTheTree(child, aReady, aTargetConfig, + aCompositor, aHasRemote, aWillResolvePlugins, + aDidResolvePlugins); } } @@ -111,7 +118,6 @@ AsyncCompositionManager::AsyncCompositionManager(LayerManagerComposite* aManager , mLayersUpdated(false) , mPaintSyncId(0) , mReadyForCompose(true) - , mHasRemoteContent(false) { } @@ -120,19 +126,35 @@ AsyncCompositionManager::~AsyncCompositionManager() } void -AsyncCompositionManager::ResolveRefLayers(bool aResolvePlugins) +AsyncCompositionManager::ResolveRefLayers(CompositorParent* aCompositor, + bool* aHasRemoteContent, + bool* aResolvePlugins) { + if (aHasRemoteContent) { + *aHasRemoteContent = false; + } + if (!mLayerManager->GetRoot()) { return; } mReadyForCompose = true; - mHasRemoteContent = false; + bool hasRemoteContent = false; + bool willResolvePlugins = (aResolvePlugins && *aResolvePlugins); + bool didResolvePlugins = false; WalkTheTree(mLayerManager->GetRoot(), mReadyForCompose, - mHasRemoteContent, mTargetConfig, - aResolvePlugins); + aCompositor, + hasRemoteContent, + willResolvePlugins, + didResolvePlugins); + if (aHasRemoteContent) { + *aHasRemoteContent = hasRemoteContent; + } + if (aResolvePlugins) { + *aResolvePlugins = didResolvePlugins; + } } void @@ -141,12 +163,13 @@ AsyncCompositionManager::DetachRefLayers() if (!mLayerManager->GetRoot()) { return; } + CompositorParent* dummy = nullptr; bool ignored = false; WalkTheTree(mLayerManager->GetRoot(), mReadyForCompose, - ignored, mTargetConfig, - ignored); + dummy, + ignored, ignored, ignored); } void diff --git a/gfx/layers/composite/AsyncCompositionManager.h b/gfx/layers/composite/AsyncCompositionManager.h index a41f36add210..efad498e1edd 100644 --- a/gfx/layers/composite/AsyncCompositionManager.h +++ b/gfx/layers/composite/AsyncCompositionManager.h @@ -26,6 +26,7 @@ class AsyncPanZoomController; class Layer; class LayerManagerComposite; class AutoResolveRefLayers; +class CompositorParent; // Represents (affine) transforms that are calculated from a content view. struct ViewTransform { @@ -117,10 +118,6 @@ public: // True if the underlying layer tree is ready to be composited. bool ReadyForCompose() { return mReadyForCompose; } - // Indicates if during the last composition remote content was detected. - // Updated in CompositorParent's CompositeToTarget. - bool HasRemoteContent() { return mHasRemoteContent; } - // Returns true if the next composition will be the first for a // particular document. bool IsFirstPaint() { return mIsFirstPaint; } @@ -189,8 +186,15 @@ private: * * For reach RefLayer in our layer tree, look up its referent and connect it * to the layer tree, if found. + * aHasRemoteContent - indicates if the layer tree contains a remote reflayer. + * May be null. + * aResolvePlugins - incoming value indicates if plugin windows should be + * updated through a call on aCompositor's UpdatePluginWindowState. Applies + * to linux and windows only, may be null. On return value indicates + * if any updates occured. */ - void ResolveRefLayers(bool aResolvePlugins); + void ResolveRefLayers(CompositorParent* aCompositor, bool* aHasRemoteContent, + bool* aResolvePlugins); /** * Detaches all referents resolved by ResolveRefLayers. @@ -220,7 +224,6 @@ private: int32_t mPaintSyncId; bool mReadyForCompose; - bool mHasRemoteContent; gfx::Matrix mWorldTransform; LayerTransformRecorder mLayerTransformRecorder; @@ -231,11 +234,13 @@ MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(AsyncCompositionManager::TransformsToSkip) class MOZ_STACK_CLASS AutoResolveRefLayers { public: explicit AutoResolveRefLayers(AsyncCompositionManager* aManager, - bool aResolvePlugins = false) : + CompositorParent* aCompositor = nullptr, + bool* aHasRemoteContent = nullptr, + bool* aResolvePlugins = nullptr) : mManager(aManager) { if (mManager) { - mManager->ResolveRefLayers(aResolvePlugins); + mManager->ResolveRefLayers(aCompositor, aHasRemoteContent, aResolvePlugins); } } From 2d784d03915488a100e2c507e486e3bfd3bce0e0 Mon Sep 17 00:00:00 2001 From: Jim Mathies Date: Tue, 6 Oct 2015 14:23:24 -0500 Subject: [PATCH 071/228] Bug 1137944 - On Windows defer composition until we receive confirmation plugin window metrics have been updated. r=roc --- gfx/layers/ipc/CompositorChild.cpp | 6 +++ gfx/layers/ipc/CompositorParent.cpp | 67 ++++++++++++++++++++++++++++- gfx/layers/ipc/CompositorParent.h | 13 +++++- gfx/layers/ipc/PCompositor.ipdl | 5 +++ 4 files changed, 88 insertions(+), 3 deletions(-) diff --git a/gfx/layers/ipc/CompositorChild.cpp b/gfx/layers/ipc/CompositorChild.cpp index 42b2a89f892c..655b2fab00fe 100644 --- a/gfx/layers/ipc/CompositorChild.cpp +++ b/gfx/layers/ipc/CompositorChild.cpp @@ -318,6 +318,9 @@ CompositorChild::RecvUpdatePluginConfigurations(const nsIntPoint& aContentOffset // Any plugins we didn't update need to be hidden, as they are // not associated with visible content. nsIWidget::UpdateRegisteredPluginWindowVisibility((uintptr_t)parent, visiblePluginIds); +#if defined(XP_WIN) + SendRemotePluginsReady(); +#endif return true; #endif // !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK) } @@ -333,6 +336,9 @@ CompositorChild::RecvHideAllPlugins(const uintptr_t& aParentWidget) MOZ_ASSERT(NS_IsMainThread()); nsTArray list; nsIWidget::UpdateRegisteredPluginWindowVisibility(aParentWidget, list); +#if defined(XP_WIN) + SendRemotePluginsReady(); +#endif return true; #endif // !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK) } diff --git a/gfx/layers/ipc/CompositorParent.cpp b/gfx/layers/ipc/CompositorParent.cpp index 57b309079385..97137766bb6b 100644 --- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -56,6 +56,7 @@ #include "nsTArray.h" // for nsTArray #include "nsThreadUtils.h" // for NS_IsMainThread #include "nsXULAppAPI.h" // for XRE_GetIOMessageLoop +#include "nsIXULRuntime.h" // for BrowserTabsRemoteAutostart #ifdef XP_WIN #include "mozilla/layers/CompositorD3D11.h" #include "mozilla/layers/CompositorD3D9.h" @@ -554,6 +555,9 @@ CompositorParent::CompositorParent(nsIWidget* aWidget, #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) , mLastPluginUpdateLayerTreeId(0) #endif +#if defined(XP_WIN) + , mPluginUpdateResponsePending(false) +#endif { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(CompositorThread(), @@ -1043,13 +1047,57 @@ CompositorParent::CompositeToTarget(DrawTarget* aTarget, const gfx::IntRect* aRe return; } - AutoResolveRefLayers resolve(mCompositionManager, true); +#if defined(XP_WIN) + // Still waiting on plugin update confirmation + if (mPluginUpdateResponsePending) { + return; + } +#endif + + bool hasRemoteContent = false; + bool pluginsUpdatedFlag = true; + AutoResolveRefLayers resolve(mCompositionManager, this, + &hasRemoteContent, + &pluginsUpdatedFlag); #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) + /* + * AutoResolveRefLayers handles two tasks related to Windows and Linux + * plugin window management: + * 1) calculating if we have remote content in the view. If we do not have + * remote content, all plugin windows for this CompositorParent (window) + * can be hidden since we do not support plugins in chrome when running + * under e10s. + * 2) Updating plugin position, size, and clip. We do this here while the + * remote layer tree is hooked up to to chrome layer tree. This is needed + * since plugin clipping can depend on chrome (for example, due to tab modal + * prompts). Updates in step 2 are applied via an async ipc message sent + * to the main thread. + * Windows specific: The compositor will wait for confirmation that plugin + * updates have been applied before painting. Deferment of painting is + * indicated by the mPluginUpdateResponsePending flag. The main thread + * messages back using the RemotePluginsReady async ipc message. + * This is neccessary since plugin windows can leave remnants of window + * content if moved after the underlying window paints. + */ +#if defined(XP_WIN) + if (pluginsUpdatedFlag) { + mPluginUpdateResponsePending = true; + return; + } +#endif + // We do not support plugins in local content. When switching tabs // to local pages, hide every plugin associated with the window. - if (!mCompositionManager->HasRemoteContent()) { + if (!hasRemoteContent && BrowserTabsRemoteAutostart() && + mCachedPluginData.Length()) { unused << SendHideAllPlugins((uintptr_t)GetWidget()); + mCachedPluginData.Clear(); +#if defined(XP_WIN) + // Wait for confirmation the hide operation is complete. + mPluginUpdateResponsePending = true; + return; +#endif } #endif @@ -1129,6 +1177,20 @@ CompositorParent::CompositeToTarget(DrawTarget* aTarget, const gfx::IntRect* aRe profiler_tracing("Paint", "Composite", TRACING_INTERVAL_END); } +bool +CompositorParent::RecvRemotePluginsReady() +{ +#if defined(XP_WIN) + mPluginUpdateResponsePending = false; + ScheduleComposition(); + return true; +#else + NS_NOTREACHED("CompositorParent::RecvRemotePluginsReady calls " + "unexpected on this platform."); + return false; +#endif +} + void CompositorParent::ForceComposeToTarget(DrawTarget* aTarget, const gfx::IntRect* aRect) { @@ -1744,6 +1806,7 @@ public: const nsTArray& aTargets) override; virtual AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aParent) override; + virtual bool RecvRemotePluginsReady() override { return false; } void DidComposite(uint64_t aId, TimeStamp& aCompositeStart, diff --git a/gfx/layers/ipc/CompositorParent.h b/gfx/layers/ipc/CompositorParent.h index 711fd3d69437..711c05f441d5 100644 --- a/gfx/layers/ipc/CompositorParent.h +++ b/gfx/layers/ipc/CompositorParent.h @@ -386,9 +386,15 @@ public: * Calculates and requests the main thread update plugin positioning, clip, * and visibility via ipc. */ - void UpdatePluginWindowState(uint64_t aId); + bool UpdatePluginWindowState(uint64_t aId); #endif + /** + * Main thread response for a plugin visibility request made by the + * compositor thread. + */ + virtual bool RecvRemotePluginsReady() override; + /** * Used by the profiler to denote when a vsync occured */ @@ -485,6 +491,11 @@ protected: nsIntRegion mPluginsLayerVisibleRegion; nsTArray mCachedPluginData; #endif +#if defined(XP_WIN) + // indicates if we are currently waiting on a plugin update confirmation. + // When this is true, composition is currently on hold. + bool mPluginUpdateResponsePending; +#endif DISALLOW_EVIL_CONSTRUCTORS(CompositorParent); }; diff --git a/gfx/layers/ipc/PCompositor.ipdl b/gfx/layers/ipc/PCompositor.ipdl index a19c193ac5aa..96cf221d8090 100644 --- a/gfx/layers/ipc/PCompositor.ipdl +++ b/gfx/layers/ipc/PCompositor.ipdl @@ -82,6 +82,11 @@ child: async ClearCachedResources(uint64_t id); parent: + /** + * Confirmation callback for UpdatePluginConfigurations and HideAllPlugins. + */ + async RemotePluginsReady(); + // Child sends the parent a request for fill ratio numbers. async RequestOverfill(); From 732721ad2a010e64bc72c186d7c476913aa159da Mon Sep 17 00:00:00 2001 From: Jim Mathies Date: Tue, 6 Oct 2015 14:23:24 -0500 Subject: [PATCH 072/228] Bug 1137944 - Add support for hiding plugin windows during async dom scroll operations managed in the content process. r=roc --- layout/generic/nsGfxScrollFrame.cpp | 38 +++++++++++++++++++++++++++++ layout/generic/nsGfxScrollFrame.h | 8 ++++++ layout/generic/nsPluginFrame.cpp | 29 ++++++++++++++++++++++ layout/generic/nsPluginFrame.h | 10 ++++++++ 4 files changed, 85 insertions(+) diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index f82d587d4c66..ebca12c9ca01 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -45,6 +45,7 @@ #include "nsSMILKeySpline.h" #include "nsSubDocumentFrame.h" #include "nsSVGOuterSVGFrame.h" +#include "nsIObjectLoadingContent.h" #include "mozilla/Attributes.h" #include "ScrollbarActivity.h" #include "nsRefreshDriver.h" @@ -57,6 +58,7 @@ #include "gfxPrefs.h" #include "AsyncScrollBase.h" #include "UnitTransforms.h" +#include "nsPluginFrame.h" #include #include #include @@ -1852,6 +1854,7 @@ ScrollFrameHelper::ScrollFrameHelper(nsContainerFrame* aOuter, , mTransformingByAPZ(false) , mZoomableByAPZ(false) , mVelocityQueue(aOuter->PresContext()) + , mAsyncScrollEvent(END) { if (LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars) != 0) { mScrollbarActivity = new ScrollbarActivity(do_QueryFrame(aOuter)); @@ -1958,6 +1961,8 @@ ScrollFrameHelper::AsyncScrollCallback(ScrollFrameHelper* aInstance, void ScrollFrameHelper::CompleteAsyncScroll(const nsRect &aRange, nsIAtom* aOrigin) { + NotifyPluginFrames(END); + // Apply desired destination range since this is the last step of scrolling. mAsyncSmoothMSDScroll = nullptr; mAsyncScroll = nullptr; @@ -1971,6 +1976,38 @@ ScrollFrameHelper::CompleteAsyncScroll(const nsRect &aRange, nsIAtom* aOrigin) mDestination = GetScrollPosition(); } +#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) +static void +NotifyPluginFramesCallback(nsISupports* aSupports, void* aFlag) +{ + nsCOMPtr content = do_QueryInterface(aSupports); + if (content) { + nsIFrame *frame = content->GetPrimaryFrame(); + if (frame) { + nsPluginFrame* plugin = do_QueryFrame(frame); + if (plugin) { + plugin->SetScrollVisibility(aFlag != nullptr); + } + } + } +} +#endif + +void +ScrollFrameHelper::NotifyPluginFrames(AsyncScrollEventType aEvent) +{ +#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) + if (XRE_IsContentProcess()) { + if (aEvent != mAsyncScrollEvent) { + nsPresContext* presContext = mOuter->PresContext(); + presContext->Document()->EnumerateActivityObservers(NotifyPluginFramesCallback, + (void*)(aEvent == BEGIN)); + mAsyncScrollEvent = aEvent; + } + } +#endif +} + void ScrollFrameHelper::ScrollToCSSPixels(const CSSIntPoint& aScrollPosition, nsIScrollableFrame::ScrollMode aMode) @@ -2125,6 +2162,7 @@ ScrollFrameHelper::ScrollToWithOrigin(nsPoint aScrollPosition, mAsyncScroll->mIsSmoothScroll = isSmoothScroll; if (isSmoothScroll) { + NotifyPluginFrames(BEGIN); mAsyncScroll->InitSmoothScroll(now, mDestination, aOrigin, range, currentVelocity); } else { mAsyncScroll->Init(range); diff --git a/layout/generic/nsGfxScrollFrame.h b/layout/generic/nsGfxScrollFrame.h index 6bcb51d08344..b6b44fdce5ae 100644 --- a/layout/generic/nsGfxScrollFrame.h +++ b/layout/generic/nsGfxScrollFrame.h @@ -558,6 +558,14 @@ protected: void CompleteAsyncScroll(const nsRect &aRange, nsIAtom* aOrigin = nullptr); + /* + * Helper that notifies plugins about async smooth scroll operations managed + * by nsGfxScrollFrame. + */ + enum AsyncScrollEventType { BEGIN, END }; + void NotifyPluginFrames(AsyncScrollEventType aEvent); + AsyncScrollEventType mAsyncScrollEvent; + static void EnsureImageVisPrefsCached(); static bool sImageVisPrefsCached; // The number of scrollports wide/high to expand when looking for images. diff --git a/layout/generic/nsPluginFrame.cpp b/layout/generic/nsPluginFrame.cpp index 81f248f893fb..37bfbdfc2ac4 100644 --- a/layout/generic/nsPluginFrame.cpp +++ b/layout/generic/nsPluginFrame.cpp @@ -157,6 +157,7 @@ nsPluginFrame::nsPluginFrame(nsStyleContext* aContext) : nsPluginFrameSuper(aContext) , mInstanceOwner(nullptr) , mReflowCallbackPosted(false) + , mIsHiddenDueToScroll(false) { MOZ_LOG(GetObjectFrameLog(), LogLevel::Debug, ("Created new nsPluginFrame %p\n", this)); @@ -764,6 +765,23 @@ nsPluginFrame::IsHidden(bool aCheckVisibilityStyle) const return false; } +// Clips windowed plugin frames during remote content scroll operations managed +// by nsGfxScrollFrame. +void +nsPluginFrame::SetScrollVisibility(bool aState) +{ + // Limit this setting to windowed plugins by checking if we have a widget + if (mWidget) { + bool changed = mIsHiddenDueToScroll != aState; + mIsHiddenDueToScroll = aState; + // Force a paint so plugin window visibility gets flushed via + // the compositor. + if (changed) { + SchedulePaint(); + } + } +} + mozilla::LayoutDeviceIntPoint nsPluginFrame::GetRemoteTabChromeOffset() { @@ -1098,6 +1116,11 @@ nsPluginFrame::DidSetWidgetGeometry() bool nsPluginFrame::IsOpaque() const { + // Insure underlying content gets painted when we clip windowed plugins + // during remote content scroll operations managed by nsGfxScrollFrame. + if (mIsHiddenDueToScroll) { + return false; + } #if defined(XP_MACOSX) return false; #elif defined(MOZ_WIDGET_ANDROID) @@ -1143,6 +1166,12 @@ nsPluginFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { + // Clip windowed plugin frames from the list during remote content scroll + // operations managed by nsGfxScrollFrame. + if (mIsHiddenDueToScroll) { + return; + } + // XXX why are we painting collapsed object frames? if (!IsVisibleOrCollapsedForPainting(aBuilder)) return; diff --git a/layout/generic/nsPluginFrame.h b/layout/generic/nsPluginFrame.h index 611839ca7243..32556026daaf 100644 --- a/layout/generic/nsPluginFrame.h +++ b/layout/generic/nsPluginFrame.h @@ -24,6 +24,7 @@ #undef GetClassName #undef GetBinaryType #undef RemoveDirectory +#undef LoadIcon #endif class nsPresContext; @@ -199,6 +200,11 @@ public: void SetInstanceOwner(nsPluginInstanceOwner* aOwner); + /** + * Helper for hiding windowed plugins during non-apz scroll operations. + */ + void SetScrollVisibility(bool aState); + protected: explicit nsPluginFrame(nsStyleContext* aContext); virtual ~nsPluginFrame(); @@ -302,6 +308,10 @@ private: // This is only non-null while we have a plugin registered for geometry // updates. nsRefPtr mRootPresContextRegisteredWith; + + // Tracks windowed plugin visibility during scroll operations. See + // SetScrollVisibility. + bool mIsHiddenDueToScroll; }; class nsDisplayPlugin : public nsDisplayItem { From d44a5df7b4c0755f2ee8259cefae9b135309ae36 Mon Sep 17 00:00:00 2001 From: Jim Mathies Date: Tue, 6 Oct 2015 14:23:24 -0500 Subject: [PATCH 073/228] Bug 1137944 - Add a pref to control plugin window hiding. r=roc --- gfx/thebes/gfxPrefs.h | 1 + layout/generic/nsGfxScrollFrame.cpp | 3 +++ 2 files changed, 4 insertions(+) diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index c1b0b9f4c70f..96b4abe55709 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -240,6 +240,7 @@ private: DECL_GFX_PREF(Live, "gfx.direct2d.use1_1", Direct2DUse1_1, bool, false); DECL_GFX_PREF(Live, "gfx.direct2d.allow1_0", Direct2DAllow1_0, bool, false); DECL_GFX_PREF(Live, "gfx.draw-color-bars", CompositorDrawColorBars, bool, false); + DECL_GFX_PREF(Once, "gfx.e10s.hide-plugins-for-scroll", HidePluginsForScroll, bool, true); DECL_GFX_PREF(Once, "gfx.font_rendering.directwrite.force-enabled", DirectWriteFontRenderingForceEnabled, bool, false); DECL_GFX_PREF(Live, "gfx.gralloc.fence-with-readpixels", GrallocFenceWithReadPixels, bool, false); DECL_GFX_PREF(Live, "gfx.layerscope.enabled", LayerScopeEnabled, bool, false); diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index ebca12c9ca01..e9d8ec90af07 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -1997,6 +1997,9 @@ void ScrollFrameHelper::NotifyPluginFrames(AsyncScrollEventType aEvent) { #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) + if (!gfxPrefs::HidePluginsForScroll()) { + return; + } if (XRE_IsContentProcess()) { if (aEvent != mAsyncScrollEvent) { nsPresContext* presContext = mOuter->PresContext(); From ff9bcb2aeccbba9cf0ebf3a1adc947b77ed0d1be Mon Sep 17 00:00:00 2001 From: Jim Mathies Date: Tue, 6 Oct 2015 14:23:24 -0500 Subject: [PATCH 074/228] Bug 1137944 - Add tests. r=roc --- dom/plugins/test/mochitest/browser.ini | 5 + .../test/mochitest/browser_bug1163570.js | 22 --- .../test/mochitest/browser_bug1196539.js | 46 +---- .../test/mochitest/browser_pluginscroll.js | 173 ++++++++++++++++++ .../browser_tabswitchbetweenplugins.js | 105 +++++++++++ dom/plugins/test/mochitest/head.js | 134 ++++++++++++++ dom/plugins/test/mochitest/plugin_test.html | 1 + 7 files changed, 421 insertions(+), 65 deletions(-) create mode 100644 dom/plugins/test/mochitest/browser_pluginscroll.js create mode 100644 dom/plugins/test/mochitest/browser_tabswitchbetweenplugins.js create mode 100644 dom/plugins/test/mochitest/head.js diff --git a/dom/plugins/test/mochitest/browser.ini b/dom/plugins/test/mochitest/browser.ini index a0dc6d4807d0..b169c46f279f 100644 --- a/dom/plugins/test/mochitest/browser.ini +++ b/dom/plugins/test/mochitest/browser.ini @@ -1,8 +1,13 @@ [DEFAULT] support-files = + head.js plugin_test.html [browser_bug1163570.js] skip-if = (!e10s || os != "win") [browser_bug1196539.js] skip-if = (!e10s || os != "win") +[browser_tabswitchbetweenplugins.js] +skip-if = (!e10s || os != "win") +[browser_pluginscroll.js] +skip-if = (!e10s || os != "win") diff --git a/dom/plugins/test/mochitest/browser_bug1163570.js b/dom/plugins/test/mochitest/browser_bug1163570.js index 6f55fe371e02..817776bd9330 100644 --- a/dom/plugins/test/mochitest/browser_bug1163570.js +++ b/dom/plugins/test/mochitest/browser_bug1163570.js @@ -1,27 +1,5 @@ var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/"); -// Returns the chrome side nsIPluginTag for this plugin -function getTestPlugin(aName) { - let pluginName = aName || "Test Plug-in"; - let ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost); - let tags = ph.getPluginTags(); - - // Find the test plugin - for (let i = 0; i < tags.length; i++) { - if (tags[i].name == pluginName) - return tags[i]; - } - ok(false, "Unable to find plugin"); - return null; -} - -// Set the test plugin state, disabling features like click-to-play -function setTestPluginEnabledState(newEnabledState, pluginName) { - let name = pluginName || "Test Plug-in"; - let plugin = getTestPlugin(name); - plugin.enabledState = newEnabledState; -} - // simple tab load helper, pilfered from browser plugin tests function promiseTabLoad(tab, url, eventType="load") { return new Promise((resolve, reject) => { diff --git a/dom/plugins/test/mochitest/browser_bug1196539.js b/dom/plugins/test/mochitest/browser_bug1196539.js index 874bdd19f922..be84b63f305d 100644 --- a/dom/plugins/test/mochitest/browser_bug1196539.js +++ b/dom/plugins/test/mochitest/browser_bug1196539.js @@ -1,45 +1,5 @@ let gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/"); -// Returns the chrome side nsIPluginTag for this plugin -function getTestPlugin(aName) { - let pluginName = aName || "Test Plug-in"; - let ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost); - let tags = ph.getPluginTags(); - - // Find the test plugin - for (let i = 0; i < tags.length; i++) { - if (tags[i].name == pluginName) - return tags[i]; - } - ok(false, "Unable to find plugin"); - return null; -} - -// Set the test plugin state, disabling features like click-to-play -function setTestPluginEnabledState(newEnabledState, pluginName) { - let name = pluginName || "Test Plug-in"; - let plugin = getTestPlugin(name); - plugin.enabledState = newEnabledState; -} - -function promiseNewTabSwitched() { - return new Promise(resolve => { - gBrowser.addEventListener("TabSwitchDone", function onSwitch() { - gBrowser.removeEventListener("TabSwitchDone", onSwitch); - executeSoon(resolve); - }); - }); -} - -function waitForMs(aMs) { - return new Promise((resolve) => { - setTimeout(done, aMs); - function done() { - resolve(true); - } - }); -} - function checkPaintCount(aCount) { ok(aCount != 0, "paint count can't be greater than zero, count was " + aCount); ok(aCount < kMaxPaints, "paint count should be within limits, count was " + aCount); @@ -82,7 +42,7 @@ add_task(function* () { }); // select plugin tab - tabSwitchedPromise = promiseNewTabSwitched(); + tabSwitchedPromise = waitTabSwitched(); gBrowser.selectedTab = pluginTab; yield tabSwitchedPromise; @@ -105,7 +65,7 @@ add_task(function* () { checkPaintCount(result); // select home tab - tabSwitchedPromise = promiseNewTabSwitched(); + tabSwitchedPromise = waitTabSwitched(); gBrowser.selectedTab = homeTab; yield tabSwitchedPromise; @@ -142,7 +102,7 @@ add_task(function* () { }); // select plugin tab - tabSwitchedPromise = promiseNewTabSwitched(); + tabSwitchedPromise = waitTabSwitched(); gBrowser.selectedTab = pluginTab; yield tabSwitchedPromise; diff --git a/dom/plugins/test/mochitest/browser_pluginscroll.js b/dom/plugins/test/mochitest/browser_pluginscroll.js new file mode 100644 index 000000000000..6851fc761236 --- /dev/null +++ b/dom/plugins/test/mochitest/browser_pluginscroll.js @@ -0,0 +1,173 @@ +let gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/"); + +/** + * tests for plugin windows and scroll + */ + +function coordinatesRelativeToWindow(aX, aY, aElement) { + var targetWindow = aElement.ownerDocument.defaultView; + var scale = targetWindow.devicePixelRatio; + var rect = aElement.getBoundingClientRect(); + return { + x: targetWindow.mozInnerScreenX + ((rect.left + aX) * scale), + y: targetWindow.mozInnerScreenY + ((rect.top + aY) * scale) + }; +} + +let apzEnabled = Preferences.get("layers.async-pan-zoom.enabled", false); +let pluginHideEnabled = Preferences.get("gfx.e10s.hide-plugins-for-scroll", true); + + +add_task(function* () { + registerCleanupFunction(function () { + setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in"); + }); +}); + +add_task(function*() { + yield new Promise((resolve) => { + SpecialPowers.pushPrefEnv({ + "set": [ + ["general.smoothScroll", true], + ["general.smoothScroll.other", true], + ["general.smoothScroll.mouseWheel", true], + ["general.smoothScroll.other.durationMaxMS", 2000], + ["general.smoothScroll.other.durationMinMS", 1999], + ["general.smoothScroll.mouseWheel.durationMaxMS", 2000], + ["general.smoothScroll.mouseWheel.durationMinMS", 1999], + ]}, resolve); + }); +}); + +/* + * test plugin visibility when scrolling with scroll wheel and apz. + */ + +add_task(function* () { + let result; + + if (!apzEnabled) { + ok(true, "nothing to test, need apz"); + return; + } + + if (!pluginHideEnabled) { + ok(true, "nothing to test, need gfx.e10s.hide-plugins-for-scroll"); + return; + } + + setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in"); + + let testTab = gBrowser.selectedTab; + let pluginTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, gTestRoot + "plugin_test.html"); + + result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + return !!plugin; + }); + is(result, true, "plugin is loaded"); + + result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible(); + }); + is(result, true, "plugin is visible"); + + let nativeId = nativeVerticalWheelEventMsg(); + let utils = SpecialPowers.getDOMWindowUtils(window); + let screenCoords = coordinatesRelativeToWindow(10, 10, + gBrowser.selectedBrowser); + utils.sendNativeMouseScrollEvent(screenCoords.x, screenCoords.y, + nativeId, 0, -50, 0, 0, 0, + gBrowser.selectedBrowser); + + yield waitScrollStart(gBrowser.selectedBrowser); + + result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible(); + }); + is(result, false, "plugin is hidden"); + + yield waitScrollFinish(gBrowser.selectedBrowser); + + result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible(); + }); + is(result, true, "plugin is visible"); + + gBrowser.removeTab(pluginTab); +}); + +/* + * test visibility when scrolling with keyboard shortcuts. This circumvents apz + * and relies on dom scroll, which is what we want to target for this test. Note + * this test should only run with e10s since we do not hide plugin windows when + * scrolling in single process mode. + */ + +add_task(function* () { + let result; + + if (!pluginHideEnabled) { + ok(true, "nothing to test, need gfx.e10s.hide-plugins-for-scroll"); + return; + } + + setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in"); + + let testTab = gBrowser.selectedTab; + let pluginTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, gTestRoot + "plugin_test.html"); + + result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + return !!plugin; + }); + is(result, true, "plugin is loaded"); + + result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible(); + }); + is(result, true, "plugin is visible"); + + EventUtils.synthesizeKey("VK_END", {}); + + yield waitScrollStart(gBrowser.selectedBrowser); + + result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible(); + }); + is(result, false, "plugin is hidden"); + + yield waitScrollFinish(gBrowser.selectedBrowser); + + result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible(); + }); + is(result, false, "plugin is hidden"); + + EventUtils.synthesizeKey("VK_HOME", {}); + + yield waitScrollFinish(gBrowser.selectedBrowser); + + result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible(); + }); + is(result, true, "plugin is visible"); + + gBrowser.removeTab(pluginTab); +}); diff --git a/dom/plugins/test/mochitest/browser_tabswitchbetweenplugins.js b/dom/plugins/test/mochitest/browser_tabswitchbetweenplugins.js new file mode 100644 index 000000000000..9fad17a6e16c --- /dev/null +++ b/dom/plugins/test/mochitest/browser_tabswitchbetweenplugins.js @@ -0,0 +1,105 @@ +let gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/"); + +// tests that we get plugin updates when we flip between tabs that +// have the same plugin in the same position in the page. + +add_task(function* () { + let result, tabSwitchedPromise; + + setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in"); + + let testTab = gBrowser.selectedTab; + let pluginTab1 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, gTestRoot + "plugin_test.html"); + let pluginTab2 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, gTestRoot + "plugin_test.html"); + + result = yield ContentTask.spawn(pluginTab1.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + return !!plugin; + }); + is(result, true, "plugin1 is loaded"); + + result = yield ContentTask.spawn(pluginTab2.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + return !!plugin; + }); + is(result, true, "plugin2 is loaded"); + + // plugin tab 2 should be selected + is(gBrowser.selectedTab == pluginTab2, true, "plugin2 is selected"); + + result = yield ContentTask.spawn(pluginTab1.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible(); + }); + is(result, false, "plugin1 is hidden"); + + result = yield ContentTask.spawn(pluginTab2.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible(); + }); + is(result, true, "plugin2 is visible"); + + // select plugin1 tab + tabSwitchedPromise = waitTabSwitched(); + gBrowser.selectedTab = pluginTab1; + yield tabSwitchedPromise; + + result = yield ContentTask.spawn(pluginTab1.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible(); + }); + is(result, true, "plugin1 is visible"); + + result = yield ContentTask.spawn(pluginTab2.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible(); + }); + is(result, false, "plugin2 is hidden"); + + // select plugin2 tab + tabSwitchedPromise = waitTabSwitched(); + gBrowser.selectedTab = pluginTab2; + yield tabSwitchedPromise; + + result = yield ContentTask.spawn(pluginTab1.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible(); + }); + is(result, false, "plugin1 is hidden"); + + result = yield ContentTask.spawn(pluginTab2.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible(); + }); + is(result, true, "plugin2 is visible"); + + // select test tab + tabSwitchedPromise = waitTabSwitched(); + gBrowser.selectedTab = testTab; + yield tabSwitchedPromise; + + result = yield ContentTask.spawn(pluginTab1.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible(); + }); + is(result, false, "plugin1 is hidden"); + + result = yield ContentTask.spawn(pluginTab2.linkedBrowser, null, function*() { + let doc = content.document; + let plugin = doc.getElementById("testplugin"); + return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible(); + }); + is(result, false, "plugin2 is hidden"); + + gBrowser.removeTab(pluginTab1); + gBrowser.removeTab(pluginTab2); +}); diff --git a/dom/plugins/test/mochitest/head.js b/dom/plugins/test/mochitest/head.js new file mode 100644 index 000000000000..751179758341 --- /dev/null +++ b/dom/plugins/test/mochitest/head.js @@ -0,0 +1,134 @@ + +/** + * Waits for a tab switch. + */ +function waitTabSwitched() { + return new Promise(resolve => { + gBrowser.addEventListener("TabSwitchDone", function onSwitch() { + gBrowser.removeEventListener("TabSwitchDone", onSwitch); + executeSoon(resolve); + }); + }); +} + +/** + * Waits a specified number of miliseconds. + * + * Usage: + * let wait = yield waitForMs(2000); + * ok(wait, "2 seconds should now have elapsed"); + * + * @param aMs the number of miliseconds to wait for + * @returns a Promise that resolves to true after the time has elapsed + */ +function waitForMs(aMs) { + return new Promise((resolve) => { + setTimeout(done, aMs); + function done() { + resolve(true); + } + }); +} + +/** + * Platform string helper for nativeVerticalWheelEventMsg + */ +function getPlatform() { + if (navigator.platform.indexOf("Win") == 0) { + return "windows"; + } + if (navigator.platform.indexOf("Mac") == 0) { + return "mac"; + } + if (navigator.platform.indexOf("Linux") == 0) { + return "linux"; + } + return "unknown"; +} + +/** + * Returns a native wheel scroll event id for dom window + * uitls sendNativeMouseScrollEvent. + */ +function nativeVerticalWheelEventMsg() { + switch (getPlatform()) { + case "windows": return 0x020A; // WM_MOUSEWHEEL + case "mac": return 0; // value is unused, can be anything + case "linux": return 4; // value is unused, pass GDK_SCROLL_SMOOTH anyway + } + throw "Native wheel events not supported on platform " + getPlatform(); +} + +/** + * Waits for the first dom "scroll" event. + */ +function waitScrollStart(aTarget) { + return new Promise((resolve, reject) => { + aTarget.addEventListener("scroll", function listener(event) { + aTarget.removeEventListener("scroll", listener, true); + resolve(event); + }, true); + }); +} + +/** + * Waits for the last dom "scroll" event which generally indicates + * a scroll operation is complete. To detect this the helper waits + * 1 second intervals checking for scroll events from aTarget. If + * a scroll event is not received during that time, it considers + * the scroll operation complete. Not super accurate, be careful. + */ +function waitScrollFinish(aTarget) { + return new Promise((resolve, reject) => { + let recent = false; + let count = 0; + function listener(event) { + recent = true; + } + aTarget.addEventListener("scroll", listener, true); + setInterval(function () { + // one second passed and we didn't receive a scroll event. + if (!recent) { + aTarget.removeEventListener("scroll", listener, true); + resolve(); + return; + } + recent = false; + // ten seconds + if (count > 10) { + aTarget.removeEventListener("scroll", listener, true); + reject(); + } + }, 1000); + }); +} + +/** + * Set a plugin activation state. See nsIPluginTag for + * supported states. Affected plugin default to the first + * test plugin. + */ +function setTestPluginEnabledState(aState, aPluginName) { + let name = aPluginName || "Test Plug-in"; + let plugin = getTestPlugin(name); + plugin.enabledState = aState; +} + +/** + * Returns the chrome side nsIPluginTag for this plugin, helper for + * setTestPluginEnabledState. + */ +function getTestPlugin(aName) { + let pluginName = aName || "Test Plug-in"; + let ph = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost); + let tags = ph.getPluginTags(); + + // Find the test plugin + for (let i = 0; i < tags.length; i++) { + if (tags[i].name == pluginName) + return tags[i]; + } + ok(false, "Unable to find plugin"); + return null; +} + diff --git a/dom/plugins/test/mochitest/plugin_test.html b/dom/plugins/test/mochitest/plugin_test.html index bc2e2f742c76..55904efd2a65 100644 --- a/dom/plugins/test/mochitest/plugin_test.html +++ b/dom/plugins/test/mochitest/plugin_test.html @@ -6,5 +6,6 @@ +
From 51bda235225898c37050dc95d5956a82529b899d Mon Sep 17 00:00:00 2001 From: Jim Mathies Date: Tue, 6 Oct 2015 14:23:25 -0500 Subject: [PATCH 075/228] Bug 1137944 - Add plugin window handling for apz related notifications received by the content process. r=mstange --- layout/generic/nsGfxScrollFrame.cpp | 13 +++++++++---- layout/generic/nsGfxScrollFrame.h | 4 +++- layout/generic/nsPluginFrame.h | 2 +- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index e9d8ec90af07..2a4436030ae5 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -1854,7 +1854,7 @@ ScrollFrameHelper::ScrollFrameHelper(nsContainerFrame* aOuter, , mTransformingByAPZ(false) , mZoomableByAPZ(false) , mVelocityQueue(aOuter->PresContext()) - , mAsyncScrollEvent(END) + , mAsyncScrollEvent(END_DOM) { if (LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars) != 0) { mScrollbarActivity = new ScrollbarActivity(do_QueryFrame(aOuter)); @@ -1961,7 +1961,7 @@ ScrollFrameHelper::AsyncScrollCallback(ScrollFrameHelper* aInstance, void ScrollFrameHelper::CompleteAsyncScroll(const nsRect &aRange, nsIAtom* aOrigin) { - NotifyPluginFrames(END); + NotifyPluginFrames(END_DOM); // Apply desired destination range since this is the last step of scrolling. mAsyncSmoothMSDScroll = nullptr; @@ -2001,10 +2001,15 @@ ScrollFrameHelper::NotifyPluginFrames(AsyncScrollEventType aEvent) return; } if (XRE_IsContentProcess()) { + // Ignore 'inner' dom events triggered by apz transformations + if (mAsyncScrollEvent == BEGIN_APZ && aEvent != END_APZ) { + return; + } if (aEvent != mAsyncScrollEvent) { nsPresContext* presContext = mOuter->PresContext(); + bool begin = (aEvent == BEGIN_APZ || aEvent == BEGIN_DOM); presContext->Document()->EnumerateActivityObservers(NotifyPluginFramesCallback, - (void*)(aEvent == BEGIN)); + (void*)begin); mAsyncScrollEvent = aEvent; } } @@ -2165,7 +2170,7 @@ ScrollFrameHelper::ScrollToWithOrigin(nsPoint aScrollPosition, mAsyncScroll->mIsSmoothScroll = isSmoothScroll; if (isSmoothScroll) { - NotifyPluginFrames(BEGIN); + NotifyPluginFrames(BEGIN_DOM); mAsyncScroll->InitSmoothScroll(now, mDestination, aOrigin, range, currentVelocity); } else { mAsyncScroll->Init(range); diff --git a/layout/generic/nsGfxScrollFrame.h b/layout/generic/nsGfxScrollFrame.h index b6b44fdce5ae..660148518790 100644 --- a/layout/generic/nsGfxScrollFrame.h +++ b/layout/generic/nsGfxScrollFrame.h @@ -360,6 +360,8 @@ public: // because we have special behaviour for it when APZ scrolling is active. mOuter->SchedulePaint(); } + // Update windowed plugin visibility in response to apz scrolling events. + NotifyPluginFrames(aTransforming ? BEGIN_APZ : END_APZ); } bool IsTransformingByAPZ() const { return mTransformingByAPZ; @@ -562,7 +564,7 @@ protected: * Helper that notifies plugins about async smooth scroll operations managed * by nsGfxScrollFrame. */ - enum AsyncScrollEventType { BEGIN, END }; + enum AsyncScrollEventType { BEGIN_DOM, BEGIN_APZ, END_DOM, END_APZ }; void NotifyPluginFrames(AsyncScrollEventType aEvent); AsyncScrollEventType mAsyncScrollEvent; diff --git a/layout/generic/nsPluginFrame.h b/layout/generic/nsPluginFrame.h index 32556026daaf..b8a1d670025c 100644 --- a/layout/generic/nsPluginFrame.h +++ b/layout/generic/nsPluginFrame.h @@ -201,7 +201,7 @@ public: void SetInstanceOwner(nsPluginInstanceOwner* aOwner); /** - * Helper for hiding windowed plugins during non-apz scroll operations. + * Helper for hiding windowed plugins during async scroll operations. */ void SetScrollVisibility(bool aState); From 8302f0688c8cacb7c2d3e72685d2f4b4f2098823 Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Wed, 30 Sep 2015 09:39:34 -0700 Subject: [PATCH 076/228] Bug 1211022 - Add a type specialization for weak C++ GC thing references; r=sfink --HG-- extra : rebase_source : 12192c6bb506c7e97308260131b0a00ebb13a6e6 --- js/src/gc/Barrier.h | 5 ++ js/src/gc/Marking.cpp | 82 +++++++++++++++++++++++----- js/src/gc/Marking.h | 10 ++-- js/src/gc/Tracer.h | 7 +++ js/src/gc/Zone.h | 7 ++- js/src/jsapi-tests/moz.build | 1 + js/src/jsapi-tests/testGCWeakRef.cpp | 63 +++++++++++++++++++++ js/src/jsgc.cpp | 10 ++++ 8 files changed, 167 insertions(+), 18 deletions(-) create mode 100644 js/src/jsapi-tests/testGCWeakRef.cpp diff --git a/js/src/gc/Barrier.h b/js/src/gc/Barrier.h index 8f262715f790..0d8c95abcfdd 100644 --- a/js/src/gc/Barrier.h +++ b/js/src/gc/Barrier.h @@ -595,6 +595,11 @@ class ReadBarriered : public ReadBarrieredBase } }; +// A WeakRef pointer does not hold its target live and is automatically nulled +// out when the GC discovers that it is not reachable from any other path. +template +using WeakRef = ReadBarriered; + // Add Value operations to all Barrier types. Note, this must be defined before // HeapSlot for HeapSlot's base to get these operations. template <> diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index a53ef9c3e5dd..f8813c2351a8 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -387,6 +387,8 @@ template void DispatchToTracer(JSTracer* trc, T* thingp, const char template T DoCallback(JS::CallbackTracer* trc, T* thingp, const char* name); template void DoMarking(GCMarker* gcmarker, T* thing); template void DoMarking(GCMarker* gcmarker, T thing); +template void NoteWeakEdge(GCMarker* gcmarker, T** thingp); +template void NoteWeakEdge(GCMarker* gcmarker, T* thingp); template void @@ -402,6 +404,18 @@ js::TraceManuallyBarrieredEdge(JSTracer* trc, T* thingp, const char* name) DispatchToTracer(trc, ConvertToBase(thingp), name); } +template +void +js::TraceWeakEdge(JSTracer* trc, WeakRef* thingp, const char* name) +{ + // Non-marking tracers treat the edge strongly. + if (!trc->isMarkingTracer()) + DispatchToTracer(trc, ConvertToBase(thingp->unsafeUnbarrieredForTracing()), name); + + NoteWeakEdge(static_cast(trc), + ConvertToBase(thingp->unsafeUnbarrieredForTracing())); +} + template void js::TraceRoot(JSTracer* trc, T* thingp, const char* name) @@ -448,6 +462,7 @@ js::TraceRootRange(JSTracer* trc, size_t len, T* vec, const char* name) #define INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS(type) \ template void js::TraceEdge(JSTracer*, WriteBarrieredBase*, const char*); \ template void js::TraceManuallyBarrieredEdge(JSTracer*, type*, const char*); \ + template void js::TraceWeakEdge(JSTracer*, WeakRef*, const char*); \ template void js::TraceRoot(JSTracer*, type*, const char*); \ template void js::TraceNullableRoot(JSTracer*, type*, const char*); \ template void js::TraceRange(JSTracer*, size_t, WriteBarrieredBase*, const char*); \ @@ -705,6 +720,47 @@ DoMarking(GCMarker* gcmarker, T thing) DispatchTyped(DoMarkingFunctor(), thing, gcmarker); } +template +void +NoteWeakEdge(GCMarker* gcmarker, T** thingp) +{ + // Do per-type marking precondition checks. + if (MustSkipMarking(*thingp)) + return; + + CheckTracedThing(gcmarker, *thingp); + + // If the target is already marked, there's no need to store the edge. + if (IsMarkedUnbarriered(thingp)) + return; + + gcmarker->noteWeakEdge(thingp); +} + +template +void +NoteWeakEdge(GCMarker* gcmarker, T* thingp) +{ + MOZ_CRASH("the gc does not support tagged pointers as weak edges"); +} + +template +void +js::GCMarker::noteWeakEdge(T* edge) +{ + static_assert(IsBaseOf::Type>::value, + "edge must point to a GC pointer"); + MOZ_ASSERT((*edge)->isTenured()); + + // Note: we really want the *source* Zone here. The edge may start in a + // non-gc heap location, however, so we use the fact that cross-zone weak + // references are not allowed and use the *target's* zone. + JS::Zone::WeakEdges &weakRefs = (*edge)->asTenured().zone()->gcWeakRefs; + AutoEnterOOMUnsafeRegion oomUnsafe; + if (!weakRefs.append(reinterpret_cast(edge))) + oomUnsafe.crash("Failed to record a weak edge for sweeping."); +} + // The simplest traversal calls out to the fully generic traceChildren function // to visit the child edges. In the absence of other traversal mechanisms, this // function will rapidly grow the stack past its bounds and crash the process. @@ -2260,6 +2316,17 @@ IsMarkedInternal(T* thingp) return rv; } +bool +js::gc::IsAboutToBeFinalizedDuringSweep(TenuredCell& tenured) +{ + MOZ_ASSERT(!IsInsideNursery(&tenured)); + MOZ_ASSERT(!tenured.runtimeFromAnyThread()->isHeapMinorCollecting()); + MOZ_ASSERT(tenured.zoneFromAnyThread()->isGCSweeping()); + if (tenured.arenaHeader()->allocatedDuringIncremental) + return false; + return !tenured.isMarked(); +} + template static bool IsAboutToBeFinalizedInternal(T** thingp) @@ -2282,11 +2349,8 @@ IsAboutToBeFinalizedInternal(T** thingp) Zone* zone = thing->asTenured().zoneFromAnyThread(); if (zone->isGCSweeping()) { - if (thing->asTenured().arenaHeader()->allocatedDuringIncremental) - return false; - return !thing->asTenured().isMarked(); - } - else if (zone->isGCCompacting() && IsForwarded(thing)) { + return IsAboutToBeFinalizedDuringSweep(thing->asTenured()); + } else if (zone->isGCCompacting() && IsForwarded(thing)) { *thingp = Forwarded(thing); return false; } @@ -2328,13 +2392,6 @@ IsMarked(WriteBarrieredBase* thingp) return IsMarkedInternal(ConvertToBase(thingp->unsafeUnbarrieredForTracing())); } -template -bool -IsMarked(ReadBarrieredBase* thingp) -{ - return IsMarkedInternal(ConvertToBase(thingp->unsafeUnbarrieredForTracing())); -} - template bool IsAboutToBeFinalizedUnbarriered(T* thingp) @@ -2360,7 +2417,6 @@ IsAboutToBeFinalized(ReadBarrieredBase* thingp) #define INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS(type) \ template bool IsMarkedUnbarriered(type*); \ template bool IsMarked(WriteBarrieredBase*); \ - template bool IsMarked(ReadBarrieredBase*); \ template bool IsAboutToBeFinalizedUnbarriered(type*); \ template bool IsAboutToBeFinalized(WriteBarrieredBase*); \ template bool IsAboutToBeFinalized(ReadBarrieredBase*); diff --git a/js/src/gc/Marking.h b/js/src/gc/Marking.h index 693b46e770fd..be698e36fe63 100644 --- a/js/src/gc/Marking.h +++ b/js/src/gc/Marking.h @@ -186,6 +186,9 @@ class GCMarker : public JSTracer template void traverseEdge(S source, T* target); template void traverseEdge(S source, T target); + // Notes a weak graph edge for later sweeping. + template void noteWeakEdge(T* edge); + /* * Care must be taken changing the mark color from gray to black. The cycle * collector depends on the invariant that there are no black to gray edges @@ -390,10 +393,6 @@ template bool IsMarked(WriteBarrieredBase* thingp); -template -bool -IsMarked(ReadBarrieredBase* thingp); - template bool IsAboutToBeFinalizedUnbarriered(T* thingp); @@ -406,6 +405,9 @@ template bool IsAboutToBeFinalized(ReadBarrieredBase* thingp); +bool +IsAboutToBeFinalizedDuringSweep(TenuredCell& tenured); + inline Cell* ToMarkable(const Value& v) { diff --git a/js/src/gc/Tracer.h b/js/src/gc/Tracer.h index 63a9c14a71f0..81da218b9d3f 100644 --- a/js/src/gc/Tracer.h +++ b/js/src/gc/Tracer.h @@ -76,6 +76,13 @@ template void TraceManuallyBarrieredEdge(JSTracer* trc, T* thingp, const char* name); +// Visits a WeakRef, but does not trace its referents. If *thingp is not marked +// at the end of marking, it is replaced by nullptr. This method records +// thingp, so the edge location must not change after this function is called. +template +void +TraceWeakEdge(JSTracer* trc, WeakRef* thingp, const char* name); + // Trace all edges contained in the given array. template void diff --git a/js/src/gc/Zone.h b/js/src/gc/Zone.h index 11c902926b2f..7f39d00d4e5a 100644 --- a/js/src/gc/Zone.h +++ b/js/src/gc/Zone.h @@ -288,10 +288,15 @@ struct Zone : public JS::shadow::Zone, typedef js::Vector CompartmentVector; CompartmentVector compartments; - // This compartment's gray roots. + // This zone's gray roots. typedef js::Vector GrayRootVector; GrayRootVector gcGrayRoots; + // This zone's weak edges found via graph traversal during marking, + // preserved for re-scanning during sweeping. + using WeakEdges = js::Vector; + WeakEdges gcWeakRefs; + // A set of edges from this zone to other zones. // // This is used during GC while calculating zone groups to record edges that diff --git a/js/src/jsapi-tests/moz.build b/js/src/jsapi-tests/moz.build index d88adb788997..9ad38d24ddb6 100644 --- a/js/src/jsapi-tests/moz.build +++ b/js/src/jsapi-tests/moz.build @@ -44,6 +44,7 @@ UNIFIED_SOURCES += [ 'testGCOutOfMemory.cpp', 'testGCStoreBufferRemoval.cpp', 'testGCUniqueId.cpp', + 'testGCWeakRef.cpp', 'testGetPropertyDescriptor.cpp', 'testHashTable.cpp', 'testIndexToString.cpp', diff --git a/js/src/jsapi-tests/testGCWeakRef.cpp b/js/src/jsapi-tests/testGCWeakRef.cpp new file mode 100644 index 000000000000..ab1b17e0a7cf --- /dev/null +++ b/js/src/jsapi-tests/testGCWeakRef.cpp @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- +* 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/. */ + +#include "gc/Barrier.h" +#include "js/RootingAPI.h" + +struct MyHeap : JS::Traceable +{ + explicit MyHeap(JSObject* obj) : weak(obj) {} + js::WeakRef weak; + + static void trace(MyHeap* self, JSTracer* trc) { + js::TraceWeakEdge(trc, &self->weak, "weak"); + } +}; + +BEGIN_TEST(testGCWeakRef) +{ + // Create an object and add a property to it so that we can read the + // property back later to verify that object internals are not garbage. + JS::RootedObject obj(cx, JS_NewPlainObject(cx)); + CHECK(obj); + CHECK(JS_DefineProperty(cx, obj, "x", 42, 0)); + + // Store the object behind a weak pointer and remove other references. + Rooted heap(cx, MyHeap(obj)); + obj = nullptr; + + rt->gc.minorGC(JS::gcreason::API); + + // The minor collection should have treated the weak ref as a strong ref, + // so the object should still be live, despite not having any other live + // references. + CHECK(heap.get().weak.unbarrieredGet() != nullptr); + obj = heap.get().weak; + RootedValue v(cx); + CHECK(JS_GetProperty(cx, obj, "x", &v)); + CHECK(v.isInt32()); + CHECK(v.toInt32() == 42); + + // A full collection with a second ref should keep the object as well. + CHECK(obj == heap.get().weak); + JS_GC(rt); + CHECK(obj == heap.get().weak); + v = UndefinedValue(); + CHECK(JS_GetProperty(cx, obj, "x", &v)); + CHECK(v.isInt32()); + CHECK(v.toInt32() == 42); + + // A full collection after nulling the root should collect the object, or + // at least null out the weak reference before returning to the mutator. + obj = nullptr; + JS_GC(rt); + CHECK(heap.get().weak == nullptr); + + return true; +} +END_TEST(testGCWeakRef) + diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 80ee4ac0a62c..6eb74ceea6c1 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -4998,6 +4998,16 @@ GCRuntime::beginSweepingZoneGroup() } } + /* Clear all weakrefs that point to unmarked things. */ + for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { + for (auto edge : zone->gcWeakRefs) { + /* Edges may be present multiple times, so may already be nulled. */ + if (*edge && IsAboutToBeFinalizedDuringSweep(**edge)) + *edge = nullptr; + } + zone->gcWeakRefs.clear(); + } + FreeOp fop(rt); SweepAtomsTask sweepAtomsTask(rt); SweepInnerViewsTask sweepInnerViewsTask(rt); From 95cb7b72c990d9e913c9cb72afd8959aebcbc3a5 Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Fri, 2 Oct 2015 15:29:34 -0700 Subject: [PATCH 077/228] Bug 1211031 - Use WeakRef to manage the LazyScript to JSScript back-reference; r=jandem --HG-- extra : rebase_source : ddc0faeb3fcb3fa0bdaf873ab9cce1e1ffb29cd8 --- js/src/gc/Marking.cpp | 6 ++++++ js/src/jsfun.cpp | 2 +- js/src/jsscript.cpp | 16 +++++++--------- js/src/jsscript.h | 9 +++++---- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index f8813c2351a8..59048cf54814 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -883,6 +883,9 @@ js::GCMarker::mark(T* thing) void LazyScript::traceChildren(JSTracer* trc) { + if (script_) + TraceWeakEdge(trc, &script_, "script"); + if (function_) TraceEdge(trc, &function_, "function"); @@ -906,6 +909,9 @@ LazyScript::traceChildren(JSTracer* trc) inline void js::GCMarker::eagerlyMarkChildren(LazyScript *thing) { + if (thing->script_) + noteWeakEdge(thing->script_.unsafeUnbarrieredForTracing()); + if (thing->function_) traverseEdge(thing, static_cast(thing->function_)); diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 6e89e4b8cbe0..83367df648b9 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -1408,7 +1408,7 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext* cx, HandleFuncti // script together during bytecode compilation. Reset it now on // error. fun->initLazyScript(lazy); - if (lazy->maybeScriptUnbarriered()) + if (lazy->hasScript()) lazy->resetScript(); return false; } diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 3c8d26b889f7..2218867161d2 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -2964,14 +2964,12 @@ JSScript::finalize(FreeOp* fop) fop->runtime()->lazyScriptCache.remove(this); - if (lazyScript && lazyScript->maybeScriptUnbarriered() == this) { - // In most cases, our LazyScript's script pointer will reference this - // script. However, because sweeping can be incremental, it's - // possible LazyScript::maybeScript() already null'ed this pointer. - // Furthermore, if we unlazified the LazyScript, it will have a - // completely different JSScript. - lazyScript->resetScript(); - } + // In most cases, our LazyScript's script pointer will reference this + // script, and thus be nulled out by normal weakref processing. However, if + // we unlazified the LazyScript during incremental sweeping, it will have a + // completely different JSScript. + MOZ_ASSERT_IF(lazyScript && !IsAboutToBeFinalizedUnbarriered(&lazyScript), + !lazyScript->hasScript() || lazyScript->maybeScriptUnbarriered() != this); } static const uint32_t GSN_CACHE_THRESHOLD = 100; @@ -4172,7 +4170,7 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun, MOZ_ASSERT(!res->sourceObject()); res->setParent(enclosingScope, &sourceObjectScript->scriptSourceUnwrap()); - MOZ_ASSERT(!res->maybeScriptUnbarriered()); + MOZ_ASSERT(!res->hasScript()); if (script) res->initScript(script); diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 9502897df9fe..6688df2c9cbd 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -2071,7 +2071,7 @@ class LazyScript : public gc::TenuredCell // If non-nullptr, the script has been compiled and this is a forwarding // pointer to the result. This is a weak pointer: after relazification, we // can collect the script if there are no other pointers to it. - ReadBarrieredScript script_; + WeakRef script_; // Original function with which the lazy script is associated. HeapPtrFunction function_; @@ -2174,13 +2174,14 @@ class LazyScript : public gc::TenuredCell void resetScript(); JSScript* maybeScript() { - if (script_.unbarrieredGet() && gc::IsAboutToBeFinalized(&script_)) - script_.set(nullptr); return script_; } - JSScript* maybeScriptUnbarriered() const { + const JSScript* maybeScriptUnbarriered() const { return script_.unbarrieredGet(); } + bool hasScript() const { + return bool(script_); + } JSObject* enclosingScope() const { return enclosingScope_; From 4c3788b7e03eeacd1e3660f1aa90db90fdc04b14 Mon Sep 17 00:00:00 2001 From: Nicholas Hurley Date: Mon, 5 Oct 2015 13:13:05 -0700 Subject: [PATCH 078/228] Bug 1197847 - make debugging h2 and spdy test servers easier. r=mcmanus --HG-- extra : rebase_source : d7559f26af0fb04ae2249db4acc181ff9be6eb6b --- dom/push/test/xpcshell/test_notification_http2.js | 2 +- dom/push/test/xpcshell/test_register_error_http2.js | 2 +- dom/push/test/xpcshell/test_register_success_http2.js | 2 +- .../test/xpcshell/test_registration_success_http2.js | 2 +- .../test/xpcshell/test_unregister_success_http2.js | 2 +- netwerk/test/unit/test_altsvc.js | 2 +- netwerk/test/unit/test_http2.js | 2 +- netwerk/test/unit/test_spdy.js | 2 +- testing/xpcshell/moz-http2/moz-http2.js | 11 ++++++++++- testing/xpcshell/runxpcshelltests.py | 7 +++++-- 10 files changed, 23 insertions(+), 11 deletions(-) diff --git a/dom/push/test/xpcshell/test_notification_http2.js b/dom/push/test/xpcshell/test_notification_http2.js index 0650f7de1394..b00d0936f636 100644 --- a/dom/push/test/xpcshell/test_notification_http2.js +++ b/dom/push/test/xpcshell/test_notification_http2.js @@ -14,7 +14,7 @@ var serverPort = -1; function run_test() { var env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment); - serverPort = env.get("MOZHTTP2-PORT"); + serverPort = env.get("MOZHTTP2_PORT"); do_check_neq(serverPort, null); dump("using port " + serverPort + "\n"); diff --git a/dom/push/test/xpcshell/test_register_error_http2.js b/dom/push/test/xpcshell/test_register_error_http2.js index c3f558625f55..0b2296e61763 100644 --- a/dom/push/test/xpcshell/test_register_error_http2.js +++ b/dom/push/test/xpcshell/test_register_error_http2.js @@ -15,7 +15,7 @@ var serverPort = -1; function run_test() { var env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment); - serverPort = env.get("MOZHTTP2-PORT"); + serverPort = env.get("MOZHTTP2_PORT"); do_check_neq(serverPort, null); do_get_profile(); diff --git a/dom/push/test/xpcshell/test_register_success_http2.js b/dom/push/test/xpcshell/test_register_success_http2.js index 84c12e914e31..a993e64e6c55 100644 --- a/dom/push/test/xpcshell/test_register_success_http2.js +++ b/dom/push/test/xpcshell/test_register_success_http2.js @@ -14,7 +14,7 @@ var serverPort = -1; function run_test() { var env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment); - serverPort = env.get("MOZHTTP2-PORT"); + serverPort = env.get("MOZHTTP2_PORT"); do_check_neq(serverPort, null); do_get_profile(); diff --git a/dom/push/test/xpcshell/test_registration_success_http2.js b/dom/push/test/xpcshell/test_registration_success_http2.js index d50d1541d4c5..f59bae900035 100644 --- a/dom/push/test/xpcshell/test_registration_success_http2.js +++ b/dom/push/test/xpcshell/test_registration_success_http2.js @@ -13,7 +13,7 @@ var serverPort = -1; function run_test() { var env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment); - serverPort = env.get("MOZHTTP2-PORT"); + serverPort = env.get("MOZHTTP2_PORT"); do_check_neq(serverPort, null); do_get_profile(); diff --git a/dom/push/test/xpcshell/test_unregister_success_http2.js b/dom/push/test/xpcshell/test_unregister_success_http2.js index 0242aa1bef3e..0ad221e57a14 100644 --- a/dom/push/test/xpcshell/test_unregister_success_http2.js +++ b/dom/push/test/xpcshell/test_unregister_success_http2.js @@ -14,7 +14,7 @@ var serverPort = -1; function run_test() { var env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment); - serverPort = env.get("MOZHTTP2-PORT"); + serverPort = env.get("MOZHTTP2_PORT"); do_check_neq(serverPort, null); do_get_profile(); diff --git a/netwerk/test/unit/test_altsvc.js b/netwerk/test/unit/test_altsvc.js index f9f37d16e906..adb222bafe99 100644 --- a/netwerk/test/unit/test_altsvc.js +++ b/netwerk/test/unit/test_altsvc.js @@ -25,7 +25,7 @@ var httpsBarOrigin; // https://bar.example.com:PORT/ function run_test() { var env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment); - h2Port = env.get("MOZHTTP2-PORT"); + h2Port = env.get("MOZHTTP2_PORT"); do_check_neq(h2Port, null); do_check_neq(h2Port, ""); diff --git a/netwerk/test/unit/test_http2.js b/netwerk/test/unit/test_http2.js index 2073668c75d6..9d9fa18edbd4 100644 --- a/netwerk/test/unit/test_http2.js +++ b/netwerk/test/unit/test_http2.js @@ -942,7 +942,7 @@ function resetPrefs() { function run_test() { var env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment); - serverPort = env.get("MOZHTTP2-PORT"); + serverPort = env.get("MOZHTTP2_PORT"); do_check_neq(serverPort, null); dump("using port " + serverPort + "\n"); diff --git a/netwerk/test/unit/test_spdy.js b/netwerk/test/unit/test_spdy.js index 13938e05a2e5..8e1aa8c2c049 100644 --- a/netwerk/test/unit/test_spdy.js +++ b/netwerk/test/unit/test_spdy.js @@ -440,7 +440,7 @@ function resetPrefs() { function run_test() { var env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment); - serverPort = env.get("MOZSPDY-PORT"); + serverPort = env.get("MOZSPDY_PORT"); do_check_neq(serverPort, null); dump("using port " + serverPort + "\n"); diff --git a/testing/xpcshell/moz-http2/moz-http2.js b/testing/xpcshell/moz-http2/moz-http2.js index 277b73473286..b33acdd1dc0c 100644 --- a/testing/xpcshell/moz-http2/moz-http2.js +++ b/testing/xpcshell/moz-http2/moz-http2.js @@ -603,4 +603,13 @@ function listenok() { serverPort = server._server.address().port; console.log('HTTP2 server listening on port ' + serverPort); } -server.listen(-1, "0.0.0.0", 200, listenok); +var portSelection = -1; +var envport = process.env.MOZHTTP2_PORT; +if (envport !== undefined) { + try { + portSelection = parseInt(envport, 10); + } catch (e) { + portSelection = -1; + } +} +server.listen(portSelection, "0.0.0.0", 200, listenok); diff --git a/testing/xpcshell/runxpcshelltests.py b/testing/xpcshell/runxpcshelltests.py index 3e7823b07e91..90d2a198b655 100755 --- a/testing/xpcshell/runxpcshelltests.py +++ b/testing/xpcshell/runxpcshelltests.py @@ -981,10 +981,10 @@ class XPCShellTests(object): nodeMozInfo['hasNode'] = True searchObj = re.search( r'SPDY server listening on port (.*)', msg, 0) if searchObj: - self.env["MOZSPDY-PORT"] = searchObj.group(1) + self.env["MOZSPDY_PORT"] = searchObj.group(1) searchObj = re.search( r'HTTP2 server listening on port (.*)', msg, 0) if searchObj: - self.env["MOZHTTP2-PORT"] = searchObj.group(1) + self.env["MOZHTTP2_PORT"] = searchObj.group(1) except OSError, e: # This occurs if the subprocess couldn't be started self.log.error('Could not run %s server: %s' % (name, str(e))) @@ -992,6 +992,9 @@ class XPCShellTests(object): myDir = os.path.split(os.path.abspath(__file__))[0] startServer('moz-spdy', os.path.join(myDir, 'moz-spdy', 'moz-spdy.js')) startServer('moz-http2', os.path.join(myDir, 'moz-http2', 'moz-http2.js')) + elif os.getenv('MOZ_ASSUME_NODE_RUNNING', None): + self.log.info('Assuming required node servers are already running') + nodeMozInfo['hasNode'] = True mozinfo.update(nodeMozInfo) From 90183c451d74acb9ff68b3ff80eb231447b37971 Mon Sep 17 00:00:00 2001 From: Nicholas Hurley Date: Tue, 22 Sep 2015 19:58:14 -0700 Subject: [PATCH 079/228] Bug 1197847 - Disallow folded headers in h2. r=mcmanus This also fixes a lot of situations in which we could get a compression state out of sync with the server, which would be Very Bad. --HG-- extra : rebase_source : 53b87c3cacd34c496f4c63cddda606d005a383e5 --- netwerk/protocol/http/Http2Compression.cpp | 122 +++++++++++++++------ netwerk/protocol/http/Http2Session.cpp | 14 ++- netwerk/protocol/http/Http2Stream.cpp | 4 +- netwerk/test/unit/test_http2.js | 78 +++++++++++-- testing/xpcshell/moz-http2/moz-http2.js | 81 +++++++++++++- 5 files changed, 251 insertions(+), 48 deletions(-) diff --git a/netwerk/protocol/http/Http2Compression.cpp b/netwerk/protocol/http/Http2Compression.cpp index 3e4bf519cbd5..d718cb4a4b4f 100644 --- a/netwerk/protocol/http/Http2Compression.cpp +++ b/netwerk/protocol/http/Http2Compression.cpp @@ -360,7 +360,9 @@ Http2Decompressor::DecodeHeaderBlock(const uint8_t *data, uint32_t datalen, mIsPush = isPush; nsresult rv = NS_OK; + nsresult softfail_rv = NS_OK; while (NS_SUCCEEDED(rv) && (mOffset < datalen)) { + bool modifiesTable = true; if (mData[mOffset] & 0x80) { rv = DoIndexed(); LOG(("Decompressor state after indexed")); @@ -371,16 +373,37 @@ Http2Decompressor::DecodeHeaderBlock(const uint8_t *data, uint32_t datalen, rv = DoContextUpdate(); LOG(("Decompressor state after context update")); } else if (mData[mOffset] & 0x10) { + modifiesTable = false; rv = DoLiteralNeverIndexed(); LOG(("Decompressor state after literal never index")); } else { + modifiesTable = false; rv = DoLiteralWithoutIndex(); LOG(("Decompressor state after literal without index")); } DumpState(); + if (rv == NS_ERROR_ILLEGAL_VALUE) { + if (modifiesTable) { + // Unfortunately, we can't count on our peer now having the same state + // as us, so let's terminate the session and we can try again later. + return NS_ERROR_FAILURE; + } + + // This is an http-level error that we can handle by resetting the stream + // in the upper layers. Let's note that we saw this, then continue + // decompressing until we either hit the end of the header block or find a + // hard failure. That way we won't get an inconsistent compression state + // with the server. + softfail_rv = rv; + rv = NS_OK; + } } - return rv; + if (NS_FAILED(rv)) { + return rv; + } + + return softfail_rv; } nsresult @@ -407,7 +430,8 @@ Http2Decompressor::DecodeInteger(uint32_t prefixLen, uint32_t &accum) if (mOffset >= mDataLen) { NS_WARNING("Ran out of data to decode integer"); - return NS_ERROR_ILLEGAL_VALUE; + // This is session-fatal. + return NS_ERROR_FAILURE; } bool chainBit = mData[mOffset] & 0x80; accum += (mData[mOffset] & 0x7f) * factor; @@ -419,12 +443,16 @@ Http2Decompressor::DecodeInteger(uint32_t prefixLen, uint32_t &accum) // really big offsets are just trawling for overflows if (accum >= 0x800000) { NS_WARNING("Decoding integer >= 0x800000"); - return NS_ERROR_ILLEGAL_VALUE; + // This is not strictly fatal to the session, but given the fact that + // the value is way to large to be reasonable, let's just tell our peer + // to go away. + return NS_ERROR_FAILURE; } if (mOffset >= mDataLen) { NS_WARNING("Ran out of data to decode integer"); - return NS_ERROR_ILLEGAL_VALUE; + // This is session-fatal. + return NS_ERROR_FAILURE; } chainBit = mData[mOffset] & 0x80; accum += (mData[mOffset] & 0x7f) * factor; @@ -538,7 +566,8 @@ Http2Decompressor::OutputHeader(uint32_t index) // bounds check if (mHeaderTable.Length() <= index) { LOG(("Http2Decompressor::OutputHeader index too large %u", index)); - return NS_ERROR_ILLEGAL_VALUE; + // This is session-fatal. + return NS_ERROR_FAILURE; } return OutputHeader(mHeaderTable[index]->mName, @@ -550,8 +579,10 @@ Http2Decompressor::CopyHeaderString(uint32_t index, nsACString &name) { // NWGH - make this < index // bounds check - if (mHeaderTable.Length() <= index) - return NS_ERROR_ILLEGAL_VALUE; + if (mHeaderTable.Length() <= index) { + // This is session-fatal. + return NS_ERROR_FAILURE; + } name = mHeaderTable[index]->mName; return NS_OK; @@ -560,8 +591,10 @@ Http2Decompressor::CopyHeaderString(uint32_t index, nsACString &name) nsresult Http2Decompressor::CopyStringFromInput(uint32_t bytes, nsACString &val) { - if (mOffset + bytes > mDataLen) - return NS_ERROR_ILLEGAL_VALUE; + if (mOffset + bytes > mDataLen) { + // This is session-fatal. + return NS_ERROR_FAILURE; + } val.Assign(reinterpret_cast(mData) + mOffset, bytes); mOffset += bytes; @@ -584,21 +617,21 @@ Http2Decompressor::DecodeFinalHuffmanCharacter(HuffmanIncomingTable *table, if (entry->mPtr) { // Can't chain to another table when we're all out of bits in the encoding LOG(("DecodeFinalHuffmanCharacter trying to chain when we're out of bits")); - return NS_ERROR_ILLEGAL_VALUE; + return NS_ERROR_FAILURE; } if (bitsLeft < entry->mPrefixLen) { // We don't have enough bits to actually make a match, this is some sort of // invalid coding LOG(("DecodeFinalHuffmanCharacter does't have enough bits to match")); - return NS_ERROR_ILLEGAL_VALUE; + return NS_ERROR_FAILURE; } // This is a character! if (entry->mValue == 256) { // EOS LOG(("DecodeFinalHuffmanCharacter actually decoded an EOS")); - return NS_ERROR_ILLEGAL_VALUE; + return NS_ERROR_FAILURE; } c = static_cast(entry->mValue & 0xFF); bitsLeft -= entry->mPrefixLen; @@ -644,7 +677,7 @@ Http2Decompressor::DecodeHuffmanCharacter(HuffmanIncomingTable *table, // TODO - does this get me into trouble in the new world? // No info left in input to try to consume, we're done LOG(("DecodeHuffmanCharacter all out of bits to consume, can't chain")); - return NS_ERROR_ILLEGAL_VALUE; + return NS_ERROR_FAILURE; } // We might get lucky here! @@ -657,7 +690,7 @@ Http2Decompressor::DecodeHuffmanCharacter(HuffmanIncomingTable *table, if (entry->mValue == 256) { LOG(("DecodeHuffmanCharacter found an actual EOS")); - return NS_ERROR_ILLEGAL_VALUE; + return NS_ERROR_FAILURE; } c = static_cast(entry->mValue & 0xFF); @@ -680,7 +713,7 @@ Http2Decompressor::CopyHuffmanStringFromInput(uint32_t bytes, nsACString &val) { if (mOffset + bytes > mDataLen) { LOG(("CopyHuffmanStringFromInput not enough data")); - return NS_ERROR_ILLEGAL_VALUE; + return NS_ERROR_FAILURE; } uint32_t bytesRead = 0; @@ -704,7 +737,7 @@ Http2Decompressor::CopyHuffmanStringFromInput(uint32_t bytes, nsACString &val) if (bytesRead > bytes) { LOG(("CopyHuffmanStringFromInput read more bytes than was allowed!")); - return NS_ERROR_ILLEGAL_VALUE; + return NS_ERROR_FAILURE; } if (bitsLeft) { @@ -719,7 +752,7 @@ Http2Decompressor::CopyHuffmanStringFromInput(uint32_t bytes, nsACString &val) if (bitsLeft > 7) { LOG(("CopyHuffmanStringFromInput more than 7 bits of padding")); - return NS_ERROR_ILLEGAL_VALUE; + return NS_ERROR_FAILURE; } if (bitsLeft) { @@ -730,7 +763,7 @@ Http2Decompressor::CopyHuffmanStringFromInput(uint32_t bytes, nsACString &val) if (bits != mask) { LOG(("CopyHuffmanStringFromInput ran out of data but found possible " "non-EOS symbol")); - return NS_ERROR_ILLEGAL_VALUE; + return NS_ERROR_FAILURE; } } @@ -749,13 +782,14 @@ Http2Decompressor::DoIndexed() uint32_t index; nsresult rv = DecodeInteger(7, index); - if (NS_FAILED(rv)) + if (NS_FAILED(rv)) { return rv; + } LOG(("HTTP decompressor indexed entry %u\n", index)); if (index == 0) { - return NS_ERROR_ILLEGAL_VALUE; + return NS_ERROR_FAILURE; } // NWGH - remove this line, since we'll keep everything 1-indexed index--; // Internally, we 0-index everything, since this is, y'know, C++ @@ -775,8 +809,9 @@ Http2Decompressor::DoLiteralInternal(nsACString &name, nsACString &value, // first let's get the name uint32_t index; nsresult rv = DecodeInteger(namePrefixLen, index); - if (NS_FAILED(rv)) + if (NS_FAILED(rv)) { return rv; + } bool isHuffmanEncoded; @@ -801,8 +836,9 @@ Http2Decompressor::DoLiteralInternal(nsACString &name, nsACString &value, LOG(("Http2Decompressor::DoLiteralInternal indexed name %d %s", index, name.BeginReading())); } - if (NS_FAILED(rv)) + if (NS_FAILED(rv)) { return rv; + } // now the value uint32_t valueLen; @@ -815,8 +851,19 @@ Http2Decompressor::DoLiteralInternal(nsACString &name, nsACString &value, rv = CopyStringFromInput(valueLen, value); } } - if (NS_FAILED(rv)) + if (NS_FAILED(rv)) { return rv; + } + + int32_t newline = 0; + while ((newline = value.FindChar('\n', newline)) != -1) { + if (value[newline + 1] == ' ' || value[newline + 1] == '\t') { + LOG(("Http2Decompressor::Disallowing folded header value %s", + value.BeginReading())); + return NS_ERROR_ILLEGAL_VALUE; + } + } + LOG(("Http2Decompressor::DoLiteralInternal value %s", value.BeginReading())); return NS_OK; } @@ -833,8 +880,9 @@ Http2Decompressor::DoLiteralWithoutIndex() LOG(("HTTP decompressor literal without index %s %s\n", name.get(), value.get())); - if (NS_SUCCEEDED(rv)) + if (NS_SUCCEEDED(rv)) { rv = OutputHeader(name, value); + } return rv; } @@ -846,10 +894,12 @@ Http2Decompressor::DoLiteralWithIncremental() nsAutoCString name, value; nsresult rv = DoLiteralInternal(name, value, 6); - if (NS_SUCCEEDED(rv)) + if (NS_SUCCEEDED(rv)) { rv = OutputHeader(name, value); - if (NS_FAILED(rv)) + } + if (NS_FAILED(rv)) { return rv; + } uint32_t room = nvPair(name, value).Size(); if (room > mMaxBuffer) { @@ -884,8 +934,9 @@ Http2Decompressor::DoLiteralNeverIndexed() LOG(("HTTP decompressor literal never indexed %s %s\n", name.get(), value.get())); - if (NS_SUCCEEDED(rv)) + if (NS_SUCCEEDED(rv)) { rv = OutputHeader(name, value); + } return rv; } @@ -899,8 +950,9 @@ Http2Decompressor::DoContextUpdate() uint32_t newMaxSize; nsresult rv = DecodeInteger(5, newMaxSize); LOG(("Http2Decompressor::DoContextUpdate new maximum size %u", newMaxSize)); - if (NS_FAILED(rv)) + if (NS_FAILED(rv)) { return rv; + } return mCompressor->SetMaxBufferSizeInternal(newMaxSize); } @@ -946,13 +998,15 @@ Http2Compressor::EncodeHeaderBlock(const nsCString &nvInput, int32_t startIndex = crlfIndex + 2; crlfIndex = nvInput.Find("\r\n", false, startIndex); - if (crlfIndex == -1) + if (crlfIndex == -1) { break; + } int32_t colonIndex = nvInput.Find(":", false, startIndex, crlfIndex - startIndex); - if (colonIndex == -1) + if (colonIndex == -1) { break; + } nsDependentCSubstring name = Substring(beginBuffer + startIndex, beginBuffer + colonIndex); @@ -999,8 +1053,9 @@ Http2Compressor::EncodeHeaderBlock(const nsCString &nvInput, if (name.EqualsLiteral("content-length")) { int64_t len; nsCString tmp(value); - if (nsHttp::ParseInt64(tmp.get(), nullptr, &len)) + if (nsHttp::ParseInt64(tmp.get(), nullptr, &len)) { mParsedContentLength = len; + } } if (name.EqualsLiteral("cookie")) { @@ -1134,8 +1189,9 @@ Http2Compressor::EncodeInteger(uint32_t prefixLen, uint32_t val) q = val / 128; r = val % 128; tmp = r; - if (q) + if (q) { tmp |= 0x80; // chain bit + } val = q; mOutput->Append(reinterpret_cast(&tmp), 1); } while (q); @@ -1304,7 +1360,7 @@ nsresult Http2Compressor::SetMaxBufferSizeInternal(uint32_t maxBufferSize) { if (maxBufferSize > mMaxBufferSetting) { - return NS_ERROR_ILLEGAL_VALUE; + return NS_ERROR_FAILURE; } uint32_t removedCount = 0; diff --git a/netwerk/protocol/http/Http2Session.cpp b/netwerk/protocol/http/Http2Session.cpp index 67bc1c43a460..d4ce0fb42e8d 100644 --- a/netwerk/protocol/http/Http2Session.cpp +++ b/netwerk/protocol/http/Http2Session.cpp @@ -1284,6 +1284,9 @@ Http2Session::RecvHeaders(Http2Session *self) self->CleanupStream(self->mInputFrameDataStream, rv, PROTOCOL_ERROR); self->ResetDownstreamState(); rv = NS_OK; + } else if (NS_FAILED(rv)) { + // This is fatal to the session. + self->mGoAwayReason = COMPRESSION_ERROR; } return rv; } @@ -1688,8 +1691,17 @@ Http2Session::RecvPushPromise(Http2Session *self) return NS_OK; } - if (NS_FAILED(rv)) + if (rv == NS_ERROR_ILLEGAL_VALUE) { + // This means the decompression completed ok, but there was a problem with + // the decoded headers. Reset the stream and go away. + self->GenerateRstStream(PROTOCOL_ERROR, promisedID); + delete pushedStream; + return NS_OK; + } else if (NS_FAILED(rv)) { + // This is fatal to the session. + self->mGoAwayReason = COMPRESSION_ERROR; return rv; + } // Ownership of the pushed stream is by the transaction hash, just as it // is for a client initiated stream. Errors that aren't fatal to the diff --git a/netwerk/protocol/http/Http2Stream.cpp b/netwerk/protocol/http/Http2Stream.cpp index 0a8f2682aeef..42b23484231b 100644 --- a/netwerk/protocol/http/Http2Stream.cpp +++ b/netwerk/protocol/http/Http2Stream.cpp @@ -994,7 +994,7 @@ Http2Stream::ConvertResponseHeaders(Http2Decompressor *decompressor, aHeadersOut, false); if (NS_FAILED(rv)) { LOG3(("Http2Stream::ConvertResponseHeaders %p decode Error\n", this)); - return NS_ERROR_ILLEGAL_VALUE; + return rv; } nsAutoCString statusString; @@ -1055,7 +1055,7 @@ Http2Stream::ConvertPushHeaders(Http2Decompressor *decompressor, aHeadersOut, true); if (NS_FAILED(rv)) { LOG3(("Http2Stream::ConvertPushHeaders %p Error\n", this)); - return NS_ERROR_ILLEGAL_VALUE; + return rv; } nsCString method; diff --git a/netwerk/test/unit/test_http2.js b/netwerk/test/unit/test_http2.js index 9d9fa18edbd4..5b5d32a51c1c 100644 --- a/netwerk/test/unit/test_http2.js +++ b/netwerk/test/unit/test_http2.js @@ -47,15 +47,21 @@ Http2CheckListener.prototype = { shouldBeHttp2 : true, accum : 0, expected: -1, + shouldSucceed: true, onStartRequest: function testOnStartRequest(request, ctx) { this.onStartRequestFired = true; - if (!Components.isSuccessCode(request.status)) + if (this.shouldSucceed && !Components.isSuccessCode(request.status)) { do_throw("Channel should have a success code! (" + request.status + ")"); + } else if (!this.shouldSucceed && Components.isSuccessCode(request.status)) { + do_throw("Channel succeeded unexpectedly!"); + } do_check_true(request instanceof Components.interfaces.nsIHttpChannel); - do_check_eq(request.responseStatus, 200); - do_check_eq(request.requestSucceeded, true); + do_check_eq(request.requestSucceeded, this.shouldSucceed); + if (this.shouldSucceed) { + do_check_eq(request.responseStatus, 200); + } }, onDataAvailable: function testOnDataAvailable(request, ctx, stream, off, cnt) { @@ -67,12 +73,16 @@ Http2CheckListener.prototype = { onStopRequest: function testOnStopRequest(request, ctx, status) { do_check_true(this.onStartRequestFired); - do_check_true(Components.isSuccessCode(status)); - do_check_true(this.onDataAvailableFired); - do_check_true(this.isHttp2Connection == this.shouldBeHttp2); if (this.expected != -1) { do_check_eq(this.accum, this.expected); } + if (this.shouldSucceed) { + do_check_true(Components.isSuccessCode(status)); + do_check_true(this.onDataAvailableFired); + do_check_true(this.isHttp2Connection == this.shouldBeHttp2); + } else { + do_check_false(Components.isSuccessCode(status)); + } run_next_test(); do_test_finished(); @@ -804,6 +814,57 @@ function test_http2_continuations() { chan.asyncOpen(listener, chan); } +function Http2IllegalHpackValidationListener() { } +Http2IllegalHpackValidationListener.prototype = new Http2CheckListener(); +Http2IllegalHpackValidationListener.prototype.shouldGoAway = false; + +Http2IllegalHpackValidationListener.prototype.onStopRequest = function (request, ctx, status) { + var wentAway = (request.getResponseHeader('X-Did-Goaway') === 'yes'); + do_check_eq(wentAway, this.shouldGoAway); + + do_check_true(this.onStartRequestFired); + do_check_true(this.onDataAvailableFired); + do_check_true(this.isHttp2Connection == this.shouldBeHttp2); + + run_next_test(); + do_test_finished(); +}; + +function Http2IllegalHpackListener() { } +Http2IllegalHpackListener.prototype = new Http2CheckListener(); +Http2IllegalHpackListener.prototype.shouldGoAway = false; + +Http2IllegalHpackListener.prototype.onStopRequest = function (request, ctx, status) { + var chan = makeChan("https://localhost:" + serverPort + "/illegalhpack_validate"); + var listener = new Http2IllegalHpackValidationListener(); + listener.shouldGoAway = this.shouldGoAway; + chan.asyncOpen(listener, null); +}; + +function test_http2_illegalhpacksoft() { + var chan = makeChan("https://localhost:" + serverPort + "/illegalhpacksoft"); + var listener = new Http2IllegalHpackListener(); + listener.shouldGoAway = false; + listener.shouldSucceed = false; + chan.asyncOpen(listener, null); +} + +function test_http2_illegalhpackhard() { + var chan = makeChan("https://localhost:" + serverPort + "/illegalhpackhard"); + var listener = new Http2IllegalHpackListener(); + listener.shouldGoAway = true; + listener.shouldSucceed = false; + chan.asyncOpen(listener, null); +} + +function test_http2_folded_header() { + var chan = makeChan("https://localhost:" + serverPort + "/foldedheader"); + chan.loadGroup = loadGroup; + var listener = new Http2CheckListener(); + listener.shouldSucceed = false; + chan.asyncOpen(listener, null); +} + function test_complete() { resetPrefs(); do_test_pending(); @@ -843,6 +904,9 @@ var tests = [ test_http2_post_big , test_http2_pushapi_1 , test_http2_continuations , test_http2_blocking_download + , test_http2_illegalhpacksoft + , test_http2_illegalhpackhard + , test_http2_folded_header // Add new tests above here - best to add new tests before h1 // streams get too involved // These next two must always come in this order @@ -858,7 +922,7 @@ var current_test = 0; function run_next_test() { if (current_test < tests.length) { - dump("starting test number " + current_test + "\n"); + dump("starting test number " + current_test + "\n"); tests[current_test](); current_test++; do_test_pending(); diff --git a/testing/xpcshell/moz-http2/moz-http2.js b/testing/xpcshell/moz-http2/moz-http2.js index b33acdd1dc0c..44c521e3e696 100644 --- a/testing/xpcshell/moz-http2/moz-http2.js +++ b/testing/xpcshell/moz-http2/moz-http2.js @@ -108,11 +108,11 @@ moreData.prototype = { content = generateContent(1024*1024); this.resp.write(content); // 1mb chunk this.iter--; - if (!this.iter) { - this.resp.end(); - } else { - setTimeout(executeRunLater, 1, this); - } + if (!this.iter) { + this.resp.end(); + } else { + setTimeout(executeRunLater, 1, this); + } } }; @@ -120,12 +120,54 @@ function executeRunLater(arg) { arg.onTimeout(); } +var Compressor = http2_compression.Compressor; +var HeaderSetCompressor = http2_compression.HeaderSetCompressor; +var originalCompressHeaders = Compressor.prototype.compress; + +function insertSoftIllegalHpack(headers) { + var originalCompressed = originalCompressHeaders.apply(this, headers); + var illegalLiteral = new Buffer([ + 0x00, // Literal, no index + 0x08, // Name: not huffman encoded, 8 bytes long + 0x3a, 0x69, 0x6c, 0x6c, 0x65, 0x67, 0x61, 0x6c, // :illegal + 0x10, // Value: not huffman encoded, 16 bytes long + // REALLY NOT LEGAL + 0x52, 0x45, 0x41, 0x4c, 0x4c, 0x59, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4c, 0x45, 0x47, 0x41, 0x4c + ]); + var newBufferLength = originalCompressed.length + illegalLiteral.length; + var concatenated = new Buffer(newBufferLength); + originalCompressed.copy(concatenated, 0); + illegalLiteral.copy(concatenated, originalCompressed.length); + return concatenated; +} + +function insertHardIllegalHpack(headers) { + var originalCompressed = originalCompressHeaders.apply(this, headers); + // Now we have to add an invalid header + var illegalIndexed = HeaderSetCompressor.integer(5000, 7); + // The above returns an array of buffers, but there's only one buffer, so + // get rid of the array. + illegalIndexed = illegalIndexed[0]; + // Set the first bit to 1 to signal this is an indexed representation + illegalIndexed[0] |= 0x80; + var newBufferLength = originalCompressed.length + illegalIndexed.length; + var concatenated = new Buffer(newBufferLength); + originalCompressed.copy(concatenated, 0); + illegalIndexed.copy(concatenated, originalCompressed.length); + return concatenated; +} + var h11required_conn = null; var h11required_header = "yes"; var didRst = false; var rstConnection = null; +var illegalheader_conn = null; function handleRequest(req, res) { + // We do this first to ensure nothing goes wonky in our tests that don't want + // the headers to have something illegal in them + Compressor.prototype.compress = originalCompressHeaders; + var u = url.parse(req.url); var content = getHttpContent(u.pathname); var push, push1, push1a, push2, push3; @@ -572,6 +614,35 @@ function handleRequest(req, res) { return; } + else if (u.pathname === "/illegalhpacksoft") { + // This will cause the compressor to compress a header that is not legal, + // but only affects the stream, not the session. + illegalheader_conn = req.stream.connection; + Compressor.prototype.compress = insertSoftIllegalHpack; + // Fall through to the default response behavior + } + + else if (u.pathname === "/illegalhpackhard") { + // This will cause the compressor to insert an HPACK instruction that will + // cause a session failure. + Compressor.prototype.compress = insertHardIllegalHpack; + // Fall through to default response behavior + } + + else if (u.pathname === "/illegalhpack_validate") { + if (req.stream.connection === illegalheader_conn) { + res.setHeader('X-Did-Goaway', 'no'); + } else { + res.setHeader('X-Did-Goaway', 'yes'); + } + // Fall through to the default response behavior + } + + else if (u.pathname === "/foldedheader") { + res.setHeader('X-Folded-Header', 'this is\n folded'); + // Fall through to the default response behavior + } + res.setHeader('Content-Type', 'text/html'); if (req.httpVersionMajor != 2) { res.setHeader('Connection', 'close'); From a2244691ca0fc59bb630e4ab817c7dc25284a287 Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Tue, 6 Oct 2015 14:00:28 -0700 Subject: [PATCH 080/228] Bug 589199 - Cleanup: remove unused DEPTH_SLOT from BlockObject. (r=efaust) --- js/src/vm/ScopeObject.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/js/src/vm/ScopeObject.h b/js/src/vm/ScopeObject.h index b4828df9d0a3..0b9ff8b4d1ed 100644 --- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -608,18 +608,10 @@ class DynamicWithObject : public NestedScopeObject class BlockObject : public NestedScopeObject { - protected: - static const unsigned DEPTH_SLOT = 1; - public: static const unsigned RESERVED_SLOTS = 2; static const Class class_; - /* Return the abstract stack depth right before entering this nested scope. */ - uint32_t stackDepth() const { - return getReservedSlot(DEPTH_SLOT).toPrivateUint32(); - } - /* Return the number of variables associated with this block. */ uint32_t numVariables() const { // TODO: propertyCount() is O(n), use O(1) lastProperty()->slot() instead From 4f61fca4fabe0bef836f11f25fcef671b7af7b57 Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Tue, 6 Oct 2015 14:00:28 -0700 Subject: [PATCH 081/228] Bug 589199 - Mark non-global lexical scopes are non-extensible. (r=efaust) --- js/src/frontend/BytecodeEmitter.cpp | 6 ++++++ js/src/vm/ScopeObject.cpp | 18 ++++++++++++++++++ js/src/vm/ScopeObject.h | 8 ++++++++ 3 files changed, 32 insertions(+) diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 825e5f4a0ed1..b989cb4df7df 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -908,6 +908,12 @@ BytecodeEmitter::enterNestedScope(StmtInfoBCE* stmt, ObjectBox* objbox, StmtType if (!emitInternedObjectOp(scopeObjectIndex, JSOP_PUSHBLOCKSCOPE)) return false; } + + // Non-global block scopes are non-extensible. At this point the + // Parser has added all bindings to the StaticBlockObject, so we make + // it non-extensible. + if (!blockObj->makeNonExtensible(cx)) + return false; break; } case StmtType::WITH: diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 9af4614a485d..6475242858c3 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -804,6 +804,12 @@ const Class NonSyntacticVariablesObject::class_ = { /*****************************************************************************/ +bool +BlockObject::isExtensible() const +{ + return nonProxyIsExtensible(); +} + /* static */ ClonedBlockObject* ClonedBlockObject::create(JSContext* cx, Handle block, HandleObject enclosing) { @@ -909,6 +915,18 @@ StaticBlockObject::lookupAliasedName(PropertyName* name) return nullptr; } +bool +StaticBlockObject::makeNonExtensible(ExclusiveContext* cx) +{ + // Do not do all the work of js::PreventExtensions, as BlockObjects are + // known to be NativeObjects, have no lazy properties, and no dense + // elements. Indeed, we do not have a JSContext as parsing may happen + // off-thread. + if (!isExtensible()) + return true; + return setFlags(cx, BaseShape::NOT_EXTENSIBLE, JSObject::GENERATE_SHAPE); +} + /* static */ Shape* StaticBlockObject::addVar(ExclusiveContext* cx, Handle block, HandleId id, bool constant, unsigned index, bool* redeclared) diff --git a/js/src/vm/ScopeObject.h b/js/src/vm/ScopeObject.h index 0b9ff8b4d1ed..1d9c4a838ed5 100644 --- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -618,6 +618,10 @@ class BlockObject : public NestedScopeObject return propertyCount(); } + // Global lexical scopes are extensible. Non-global lexicals scopes are + // not. + bool isExtensible() const; + protected: /* Blocks contain an object slot for each slot i: 0 <= i < slotCount. */ const Value& slotValue(unsigned i) { @@ -742,6 +746,10 @@ class StaticBlockObject : public BlockObject return reinterpret_cast(v.toPrivate()); } + // Called by BytecodeEmitter to mark regular block scopes as + // non-extensible. By contrast, the global lexical scope is extensible. + bool makeNonExtensible(ExclusiveContext* cx); + /* * While ScopeCoordinate can generally reference up to 2^24 slots, block objects have an * additional limitation that all slot indices must be storable as uint16_t short-ids in the From aedb453377bfb738afd53e6060fcf22eda66a5cc Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Tue, 6 Oct 2015 14:00:28 -0700 Subject: [PATCH 082/228] Bug 589199 - Make a global lexical scope and hook it up to JS entry points. (r=efaust) --- js/public/Class.h | 2 +- js/src/asmjs/AsmJSLink.cpp | 3 +- js/src/frontend/BytecodeCompiler.cpp | 13 ++++- js/src/frontend/BytecodeCompiler.h | 8 +++ js/src/jit/CompileInfo.h | 1 + js/src/jsapi.cpp | 65 +++++++++++++++-------- js/src/jsfun.cpp | 14 ++--- js/src/jsscript.cpp | 12 +++-- js/src/vm/GlobalObject.cpp | 12 +++++ js/src/vm/GlobalObject.h | 5 ++ js/src/vm/HelperThreads.cpp | 18 +++++-- js/src/vm/Interpreter.cpp | 7 +-- js/src/vm/ScopeObject-inl.h | 6 ++- js/src/vm/ScopeObject.cpp | 78 +++++++++++++++++++++++++--- js/src/vm/ScopeObject.h | 30 +++++++++++ js/src/vm/SelfHosting.cpp | 17 ++++-- js/src/vm/Stack.cpp | 8 ++- 17 files changed, 243 insertions(+), 56 deletions(-) diff --git a/js/public/Class.h b/js/public/Class.h index 8aae2fcc6fa6..31c13dbd5823 100644 --- a/js/public/Class.h +++ b/js/public/Class.h @@ -697,7 +697,7 @@ struct JSClass { // application. #define JSCLASS_GLOBAL_APPLICATION_SLOTS 5 #define JSCLASS_GLOBAL_SLOT_COUNT \ - (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 3 + 35) + (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 3 + 36) #define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \ (JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n))) #define JSCLASS_GLOBAL_FLAGS \ diff --git a/js/src/asmjs/AsmJSLink.cpp b/js/src/asmjs/AsmJSLink.cpp index 78f3d64b1204..f1cf7a1bb6a2 100644 --- a/js/src/asmjs/AsmJSLink.cpp +++ b/js/src/asmjs/AsmJSLink.cpp @@ -879,8 +879,7 @@ HandleDynamicLinkFailure(JSContext* cx, const CallArgs& args, AsmJSModule& modul ? SourceBufferHolder::GiveOwnership : SourceBufferHolder::NoOwnership; SourceBufferHolder srcBuf(chars, end - begin, ownership); - if (!frontend::CompileFunctionBody(cx, &fun, options, formals, srcBuf, - /* enclosingScope = */ nullptr)) + if (!frontend::CompileFunctionBody(cx, &fun, options, formals, srcBuf)) return false; // Call the function we just recompiled. diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index 0e56102dd93d..d28303476940 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -933,11 +933,22 @@ frontend::CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, enclosingStaticScope, NotGenerator); } +bool +frontend::CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, + const ReadOnlyCompileOptions& options, + Handle formals, JS::SourceBufferHolder& srcBuf) +{ + Rooted staticLexical(cx, &cx->global()->lexicalScope().staticBlock()); + return CompileFunctionBody(cx, fun, options, formals, srcBuf, staticLexical, NotGenerator); +} + + bool frontend::CompileStarGeneratorBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyCompileOptions& options, Handle formals, JS::SourceBufferHolder& srcBuf) { - return CompileFunctionBody(cx, fun, options, formals, srcBuf, nullptr, StarGenerator); + Rooted staticLexical(cx, &cx->global()->lexicalScope().staticBlock()); + return CompileFunctionBody(cx, fun, options, formals, srcBuf, staticLexical, StarGenerator); } diff --git a/js/src/frontend/BytecodeCompiler.h b/js/src/frontend/BytecodeCompiler.h index 358020a84f69..7f03f0d19be6 100644 --- a/js/src/frontend/BytecodeCompiler.h +++ b/js/src/frontend/BytecodeCompiler.h @@ -48,6 +48,14 @@ CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyCompileOptions& options, Handle formals, JS::SourceBufferHolder& srcBuf, Handle enclosingStaticScope); + +// As above, but defaults to the global lexical scope as the enclosing static +// scope. +bool +CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, + const ReadOnlyCompileOptions& options, + Handle formals, JS::SourceBufferHolder& srcBuf); + bool CompileStarGeneratorBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyCompileOptions& options, diff --git a/js/src/jit/CompileInfo.h b/js/src/jit/CompileInfo.h index d790e00d3a66..7fd299950c6e 100644 --- a/js/src/jit/CompileInfo.h +++ b/js/src/jit/CompileInfo.h @@ -10,6 +10,7 @@ #include "jsfun.h" #include "jit/JitAllocPolicy.h" +#include "jit/JitFrames.h" #include "jit/Registers.h" #include "vm/ScopeObject.h" diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index fb3fb14580fc..29cc5a4b8a77 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3437,13 +3437,13 @@ CreateNonSyntacticScopeChain(JSContext* cx, AutoObjectVector& scopeChain, MutableHandleObject dynamicScopeObj, MutableHandle staticScopeObj) { - if (!js::CreateScopeObjectsForScopeChain(cx, scopeChain, cx->global(), dynamicScopeObj)) + Rooted globalLexical(cx, &cx->global()->lexicalScope()); + if (!js::CreateScopeObjectsForScopeChain(cx, scopeChain, globalLexical, dynamicScopeObj)) return false; - if (scopeChain.empty()) { - staticScopeObj.set(nullptr); - } else { - staticScopeObj.set(StaticNonSyntacticScopeObjects::create(cx, nullptr)); + staticScopeObj.set(&globalLexical->staticBlock()); + if (!scopeChain.empty()) { + staticScopeObj.set(StaticNonSyntacticScopeObjects::create(cx, staticScopeObj)); if (!staticScopeObj) return false; @@ -3462,7 +3462,7 @@ CreateNonSyntacticScopeChain(JSContext* cx, AutoObjectVector& scopeChain, } static bool -IsFunctionCloneable(HandleFunction fun, HandleObject dynamicScope) +IsFunctionCloneable(HandleFunction fun) { if (!fun->isInterpreted()) return true; @@ -3475,6 +3475,10 @@ IsFunctionCloneable(HandleFunction fun, HandleObject dynamicScope) if (scope->is()) return true; + // If the script is directly under the global scope, we can clone it. + if (IsStaticGlobalLexicalScope(scope)) + return true; + // If the script is an indirect eval that is immediately scoped under // the global, we can clone it. if (scope->is()) { @@ -3514,7 +3518,7 @@ CloneFunctionObject(JSContext* cx, HandleObject funobj, HandleObject dynamicScop return nullptr; } - if (!IsFunctionCloneable(fun, dynamicScope)) { + if (!IsFunctionCloneable(fun)) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_CLONE_FUNOBJ_SCOPE); return nullptr; } @@ -3531,14 +3535,16 @@ CloneFunctionObject(JSContext* cx, HandleObject funobj, HandleObject dynamicScop if (CanReuseScriptForClone(cx->compartment(), fun, dynamicScope)) { // If the script is to be reused, either the script can already handle - // non-syntactic scopes, or there is no new static scope. + // non-syntactic scopes, or there is only the standard global lexical + // scope. #ifdef DEBUG // Fail here if we OOM during debug asserting. // CloneFunctionReuseScript will delazify the script anyways, so we // are not creating an extra failure condition for DEBUG builds. if (!fun->getOrCreateScript(cx)) return nullptr; - MOZ_ASSERT(!staticScope || fun->nonLazyScript()->hasNonSyntacticScope()); + MOZ_ASSERT(IsStaticGlobalLexicalScope(staticScope) || + fun->nonLazyScript()->hasNonSyntacticScope()); #endif return CloneFunctionReuseScript(cx, fun, dynamicScope, fun->getAllocKind()); } @@ -3551,7 +3557,9 @@ namespace JS { JS_PUBLIC_API(JSObject*) CloneFunctionObject(JSContext* cx, JS::Handle funobj) { - return CloneFunctionObject(cx, funobj, cx->global(), /* staticScope = */ nullptr); + Rooted globalLexical(cx, &cx->global()->lexicalScope()); + Rooted staticLexical(cx, &globalLexical->staticBlock()); + return CloneFunctionObject(cx, funobj, globalLexical, staticLexical); } extern JS_PUBLIC_API(JSObject*) @@ -4038,14 +4046,15 @@ Compile(JSContext* cx, const ReadOnlyCompileOptions& options, SyntacticScopeOpti CHECK_REQUEST(cx); AutoLastFrameCheck lfc(cx); - Rooted staticScope(cx); + Rooted staticScope(cx, &cx->global()->lexicalScope().staticBlock()); if (scopeOption == HasNonSyntacticScope) { - staticScope = StaticNonSyntacticScopeObjects::create(cx, nullptr); + staticScope = StaticNonSyntacticScopeObjects::create(cx, staticScope); if (!staticScope) return false; } - script.set(frontend::CompileScript(cx, &cx->tempLifoAlloc(), cx->global(), + RootedObject globalLexical(cx, &cx->global()->lexicalScope()); + script.set(frontend::CompileScript(cx, &cx->tempLifoAlloc(), globalLexical, staticScope, nullptr, options, srcBuf)); return !!script; } @@ -4349,7 +4358,7 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg, // Make sure the static scope chain matches up when we have a // non-syntactic scope. - MOZ_ASSERT_IF(!enclosingDynamicScope->is(), + MOZ_ASSERT_IF(!IsGlobalLexicalScope(enclosingDynamicScope), HasNonSyntacticStaticScopeChain(enclosingStaticScope)); if (!frontend::CompileFunctionBody(cx, fun, optionsArg, formals, srcBuf, enclosingStaticScope)) @@ -4446,7 +4455,7 @@ ExecuteScript(JSContext* cx, HandleObject scope, HandleScript script, Value* rva AssertHeapIsIdle(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, scope, script); - MOZ_ASSERT_IF(!scope->is(), script->hasNonSyntacticScope()); + MOZ_ASSERT_IF(!IsGlobalLexicalScope(scope), script->hasNonSyntacticScope()); AutoLastFrameCheck lfc(cx); return Execute(cx, script, *scope, rval); } @@ -4473,13 +4482,15 @@ ExecuteScript(JSContext* cx, AutoObjectVector& scopeChain, HandleScript scriptAr MOZ_NEVER_INLINE JS_PUBLIC_API(bool) JS_ExecuteScript(JSContext* cx, HandleScript scriptArg, MutableHandleValue rval) { - return ExecuteScript(cx, cx->global(), scriptArg, rval.address()); + RootedObject globalLexical(cx, &cx->global()->lexicalScope()); + return ExecuteScript(cx, globalLexical, scriptArg, rval.address()); } MOZ_NEVER_INLINE JS_PUBLIC_API(bool) JS_ExecuteScript(JSContext* cx, HandleScript scriptArg) { - return ExecuteScript(cx, cx->global(), scriptArg, nullptr); + RootedObject globalLexical(cx, &cx->global()->lexicalScope()); + return ExecuteScript(cx, globalLexical, scriptArg, nullptr); } MOZ_NEVER_INLINE JS_PUBLIC_API(bool) @@ -4500,14 +4511,16 @@ JS::CloneAndExecuteScript(JSContext* cx, HandleScript scriptArg) { CHECK_REQUEST(cx); RootedScript script(cx, scriptArg); + Rooted globalLexical(cx, &cx->global()->lexicalScope()); if (script->compartment() != cx->compartment()) { - script = CloneGlobalScript(cx, /* enclosingScope = */ nullptr, script); + Rooted staticLexical(cx, &globalLexical->staticBlock()); + script = CloneGlobalScript(cx, staticLexical, script); if (!script) return false; js::Debugger::onNewScript(cx, script); } - return ExecuteScript(cx, cx->global(), script, nullptr); + return ExecuteScript(cx, globalLexical, script, nullptr); } static const unsigned LARGE_SCRIPT_LENGTH = 500*1024; @@ -4525,7 +4538,7 @@ Evaluate(JSContext* cx, HandleObject scope, Handle staticScope, AutoLastFrameCheck lfc(cx); - MOZ_ASSERT_IF(!scope->is(), HasNonSyntacticStaticScopeChain(staticScope)); + MOZ_ASSERT_IF(!IsGlobalLexicalScope(scope), HasNonSyntacticStaticScopeChain(staticScope)); options.setIsRunOnce(true); SourceCompressionTask sct(cx); @@ -4573,7 +4586,9 @@ Evaluate(JSContext* cx, const ReadOnlyCompileOptions& optionsArg, const char16_t* chars, size_t length, MutableHandleValue rval) { SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership); - return ::Evaluate(cx, cx->global(), nullptr, optionsArg, srcBuf, rval); + Rooted globalLexical(cx, &cx->global()->lexicalScope()); + Rooted staticLexical(cx, &globalLexical->staticBlock()); + return ::Evaluate(cx, globalLexical, staticLexical, optionsArg, srcBuf, rval); } extern JS_PUBLIC_API(bool) @@ -4589,7 +4604,9 @@ JS::Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options, return false; SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::GiveOwnership); - bool ok = ::Evaluate(cx, cx->global(), nullptr, options, srcBuf, rval); + Rooted globalLexical(cx, &cx->global()->lexicalScope()); + Rooted staticLexical(cx, &globalLexical->staticBlock()); + bool ok = ::Evaluate(cx, globalLexical, staticLexical, options, srcBuf, rval); return ok; } @@ -4613,7 +4630,9 @@ JS_PUBLIC_API(bool) JS::Evaluate(JSContext* cx, const ReadOnlyCompileOptions& optionsArg, SourceBufferHolder& srcBuf, MutableHandleValue rval) { - return ::Evaluate(cx, cx->global(), nullptr, optionsArg, srcBuf, rval); + Rooted globalLexical(cx, &cx->global()->lexicalScope()); + Rooted staticLexical(cx, &globalLexical->staticBlock()); + return ::Evaluate(cx, globalLexical, staticLexical, optionsArg, srcBuf, rval); } JS_PUBLIC_API(bool) diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 83367df648b9..080f7b82e41f 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -1821,8 +1821,9 @@ FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind gener if (!proto) return false; } + RootedObject globalLexical(cx, &global->lexicalScope()); RootedFunction fun(cx, NewFunctionWithProto(cx, nullptr, 0, - JSFunction::INTERPRETED_LAMBDA, global, + JSFunction::INTERPRETED_LAMBDA, globalLexical, anonymousAtom, proto, AllocKind::FUNCTION, TenuredObject)); if (!fun) @@ -1915,8 +1916,7 @@ FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind gener if (isStarGenerator) ok = frontend::CompileStarGeneratorBody(cx, &fun, options, formals, srcBuf); else - ok = frontend::CompileFunctionBody(cx, &fun, options, formals, srcBuf, - /* enclosingScope = */ nullptr); + ok = frontend::CompileFunctionBody(cx, &fun, options, formals, srcBuf); args.rval().setObject(*fun); return ok; } @@ -1964,10 +1964,12 @@ js::NewScriptedFunction(ExclusiveContext* cx, unsigned nargs, JSFunction::Flags flags, HandleAtom atom, gc::AllocKind allocKind /* = AllocKind::FUNCTION */, NewObjectKind newKind /* = GenericObject */, - HandleObject enclosingDynamicScope /* = nullptr */) + HandleObject enclosingDynamicScopeArg /* = nullptr */) { - return NewFunctionWithProto(cx, nullptr, nargs, flags, - enclosingDynamicScope ? enclosingDynamicScope : cx->global(), + RootedObject enclosingDynamicScope(cx, enclosingDynamicScopeArg); + if (!enclosingDynamicScope) + enclosingDynamicScope = &cx->global()->lexicalScope(); + return NewFunctionWithProto(cx, nullptr, nargs, flags, enclosingDynamicScope, atom, nullptr, allocKind, newKind); } diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 2218867161d2..dcbfb1f0680f 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -3325,7 +3325,13 @@ js::detail::CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScri MOZ_ASSERT(scriptStaticScope->is()); enclosingScope = scriptStaticScope; } else if (ssi.type() == StaticScopeIter::Block) { - enclosingScope = objects[FindScopeObjectIndex(src, ssi.block())]; + if (ssi.block().isGlobal()) { + MOZ_ASSERT(IsStaticGlobalLexicalScope(scriptStaticScope) || + scriptStaticScope->is()); + enclosingScope = scriptStaticScope; + } else { + enclosingScope = objects[FindScopeObjectIndex(src, ssi.block())]; + } } else { enclosingScope = objects[FindScopeObjectIndex(src, ssi.staticWith())]; } @@ -3475,8 +3481,8 @@ CreateEmptyScriptForClone(JSContext* cx, HandleObject enclosingScope, HandleScri JSScript* js::CloneGlobalScript(JSContext* cx, Handle enclosingScope, HandleScript src) { - // No enclosingScope means clean global. - MOZ_ASSERT(!enclosingScope || enclosingScope->is()); + MOZ_ASSERT(IsGlobalLexicalScope(enclosingScope) || + enclosingScope->is()); RootedScript dst(cx, CreateEmptyScriptForClone(cx, enclosingScope, src)); if (!dst) diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index cce3fcd68127..1812a3d9087d 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -33,6 +33,7 @@ #include "vm/PIC.h" #include "vm/RegExpStatics.h" #include "vm/RegExpStaticsObject.h" +#include "vm/ScopeObject.h" #include "vm/StopIterationObject.h" #include "jscompartmentinlines.h" @@ -257,6 +258,11 @@ GlobalObject::createInternal(JSContext* cx, const Class* clasp) if (clasp->flags & JSCLASS_HAS_PRIVATE) global->setPrivate(nullptr); + Rooted lexical(cx, ClonedBlockObject::createGlobal(cx, global)); + if (!lexical) + return nullptr; + global->setReservedSlot(LEXICAL_SCOPE, ObjectValue(*lexical)); + cx->compartment()->initGlobal(*global); if (!global->setQualifiedVarObj(cx)) @@ -309,6 +315,12 @@ GlobalObject::new_(JSContext* cx, const Class* clasp, JSPrincipals* principals, return global; } +ClonedBlockObject& +GlobalObject::lexicalScope() const +{ + return getReservedSlot(LEXICAL_SCOPE).toObject().as(); +} + /* static */ bool GlobalObject::getOrCreateEval(JSContext* cx, Handle global, MutableHandleObject eval) diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index 68a9e621ebe4..242aa43d7bb4 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -27,6 +27,8 @@ InitSharedArrayBufferClass(JSContext* cx, HandleObject obj); class Debugger; class TypedObjectModuleObject; +class StaticBlockObject; +class ClonedBlockObject; /* * Global object slots are reserved as follows: @@ -91,6 +93,7 @@ class GlobalObject : public NativeObject FROM_BUFFER_UINT8CLAMPED, /* One-off properties stored after slots for built-ins. */ + LEXICAL_SCOPE, ARRAY_ITERATOR_PROTO, STRING_ITERATOR_PROTO, LEGACY_GENERATOR_OBJECT_PROTO, @@ -142,6 +145,8 @@ class GlobalObject : public NativeObject public: + ClonedBlockObject& lexicalScope() const; + void setThrowTypeError(JSFunction* fun) { MOZ_ASSERT(getSlotRef(THROWTYPEERROR).isUndefined()); setSlot(THROWTYPEERROR, ObjectValue(*fun)); diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index fc7d292d3dbb..beb46ed4c9ca 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -1392,10 +1392,20 @@ HelperThread::handleParseWorkload() task->exclusiveContextGlobal->runtimeFromAnyThread()); SourceBufferHolder srcBuf(task->chars, task->length, SourceBufferHolder::NoOwnership); - task->script = frontend::CompileScript(task->cx, &task->alloc, - nullptr, nullptr, nullptr, - task->options, - srcBuf, + + // ! WARNING WARNING WARNING ! + // + // See comment in Parser::bindLexical about optimizing global lexical + // bindings. If we start optimizing them, passing in parseTask->cx's + // global lexical scope would be incorrect! + // + // ! WARNING WARNING WARNING ! + ExclusiveContext* parseCx = parseTask->cx; + Rooted globalLexical(parseCx, &parseCx->global()->lexicalScope()); + Rooted staticScope(parseCx, &globalLexical->staticBlock()); + task->script = frontend::CompileScript(parseCx, &parseTask->alloc, + globalLexical, staticScope, nullptr, + parseTask->options, srcBuf, /* source_ = */ nullptr, /* extraSct = */ nullptr, /* sourceObjectOut = */ &(task->sourceObject)); diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index a4a12f051325..3953d368e2d8 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -946,7 +946,8 @@ js::ExecuteKernel(JSContext* cx, HandleScript script, JSObject& scopeChainArg, c Value* result) { MOZ_ASSERT_IF(evalInFrame, type == EXECUTE_DEBUG); - MOZ_ASSERT_IF(type == EXECUTE_GLOBAL, !IsSyntacticScope(&scopeChainArg)); + MOZ_ASSERT_IF(type == EXECUTE_GLOBAL, IsGlobalLexicalScope(&scopeChainArg) || + !IsSyntacticScope(&scopeChainArg)); #ifdef DEBUG if (thisv.isObject()) { RootedObject thisObj(cx, &thisv.toObject()); @@ -993,7 +994,7 @@ js::Execute(JSContext* cx, HandleScript script, JSObject& scopeChainArg, Value* RootedObject scopeChain(cx, &scopeChainArg); MOZ_ASSERT(scopeChain == GetInnerObject(scopeChain)); - MOZ_RELEASE_ASSERT(scopeChain->is() || script->hasNonSyntacticScope(), + MOZ_RELEASE_ASSERT(IsGlobalLexicalScope(scopeChain) || script->hasNonSyntacticScope(), "Only scripts with non-syntactic scopes can be executed with " "interesting scopechains"); @@ -1595,7 +1596,7 @@ ComputeImplicitThis(JSContext* cx, HandleObject obj, MutableHandleValue vp) { vp.setUndefined(); - if (obj->is()) + if (IsGlobalLexicalScope(obj)) return true; if (IsCacheableNonGlobalScope(obj)) diff --git a/js/src/vm/ScopeObject-inl.h b/js/src/vm/ScopeObject-inl.h index dda3b2545ad1..d54ef5933a92 100644 --- a/js/src/vm/ScopeObject-inl.h +++ b/js/src/vm/ScopeObject-inl.h @@ -108,8 +108,10 @@ StaticScopeIter::hasSyntacticDynamicScopeObject() const } if (obj->template is()) return true; - if (obj->template is()) - return obj->template as().needsClone(); + if (obj->template is()) { + return obj->template as().needsClone() || + obj->template as().isGlobal(); + } if (obj->template is()) return true; if (obj->template is()) diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 6475242858c3..0a14bd78d4c6 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -289,9 +289,10 @@ CallObject::createHollowForDebug(JSContext* cx, HandleFunction callee) // This scope's parent link is never used: the DebugScopeObject that // refers to this scope carries its own parent link, which is what // Debugger uses to construct the tree of Debugger.Environment objects. So - // just parent this scope directly to the global. + // just parent this scope directly to the global lexical scope. Rooted global(cx, &callee->global()); - Rooted callobj(cx, createForFunction(cx, global, callee)); + RootedObject globalLexical(cx, &global->lexicalScope()); + Rooted callobj(cx, createForFunction(cx, globalLexical, callee)); if (!callobj) return nullptr; @@ -378,7 +379,8 @@ ModuleEnvironmentObject::create(ExclusiveContext* cx, HandleModuleObject module) // Initialize this early so that we can manipulate the scope object without // causing assertions. - scope->setEnclosingScope(cx->global()); + RootedObject globalLexical(cx, &cx->global()->lexicalScope()); + scope->setEnclosingScope(globalLexical); return scope; } @@ -848,6 +850,25 @@ ClonedBlockObject::create(JSContext* cx, Handle block, Abstr return create(cx, block, enclosing); } +/* static */ ClonedBlockObject* +ClonedBlockObject::createGlobal(JSContext* cx, Handle global) +{ + Rooted staticLexical(cx, StaticBlockObject::create(cx)); + if (!staticLexical) + return nullptr; + + // Currently the global lexical scope cannot have any bindings with frame + // slots. + staticLexical->setLocalOffset(UINT32_MAX); + staticLexical->initEnclosingScope(nullptr); + Rooted lexical(cx, ClonedBlockObject::create(cx, staticLexical, global)); + if (!lexical) + return nullptr; + if (!JSObject::setSingleton(cx, lexical)) + return nullptr; + return lexical; +} + /* static */ ClonedBlockObject* ClonedBlockObject::createHollowForDebug(JSContext* cx, Handle block) { @@ -856,9 +877,10 @@ ClonedBlockObject::createHollowForDebug(JSContext* cx, Handle global(cx, &block->global()); - Rooted obj(cx, create(cx, block, global)); + RootedObject globalLexical(cx, &global->lexicalScope()); + Rooted obj(cx, create(cx, block, globalLexical)); if (!obj) return nullptr; @@ -884,6 +906,7 @@ ClonedBlockObject::copyUnaliasedValues(AbstractFramePtr frame) ClonedBlockObject::clone(JSContext* cx, Handle clonedBlock) { Rooted staticBlock(cx, &clonedBlock->staticBlock()); + MOZ_ASSERT(!staticBlock->isExtensible()); RootedObject enclosing(cx, &clonedBlock->enclosingScope()); Rooted copy(cx, create(cx, staticBlock, enclosing)); @@ -960,10 +983,48 @@ StaticBlockObject::addVar(ExclusiveContext* cx, Handle block /* allowDictionary = */ false); } +static JSObject* +block_ThisObject(JSContext* cx, HandleObject obj) +{ + // No other block objects should ever get passed to the 'this' object + // hook. + MOZ_ASSERT(obj->as().isGlobal()); + MOZ_ASSERT(&obj->as().enclosingScope() == cx->global()); + RootedObject enclosing(cx, obj->enclosingScope()); + return GetThisObject(cx, enclosing); +} + const Class BlockObject::class_ = { "Block", JSCLASS_HAS_RESERVED_SLOTS(BlockObject::RESERVED_SLOTS) | - JSCLASS_IS_ANONYMOUS + JSCLASS_IS_ANONYMOUS, + nullptr, /* addProperty */ + nullptr, /* delProperty */ + nullptr, /* getProperty */ + nullptr, /* setProperty */ + nullptr, /* enumerate */ + nullptr, /* resolve */ + nullptr, /* mayResolve */ + nullptr, /* finalize */ + nullptr, /* call */ + nullptr, /* hasInstance */ + nullptr, /* construct */ + nullptr, /* trace */ + JS_NULL_CLASS_SPEC, + JS_NULL_CLASS_EXT, + { + nullptr, /* lookupProperty */ + nullptr, /* defineProperty */ + nullptr, /* hasProperty */ + nullptr, /* getProperty */ + nullptr, /* setProperty */ + nullptr, /* getOwnPropertyDescriptor */ + nullptr, /* deleteProperty */ + nullptr, nullptr, /* watch/unwatch */ + nullptr, /* getElements */ + nullptr, /* enumerate (native enumeration of target doesn't work) */ + block_ThisObject, + } }; template @@ -1104,6 +1165,11 @@ CloneStaticBlockObject(JSContext* cx, HandleObject enclosingScope, HandlesetAliased(i, srcBlock->isAliased(i)); } + if (!srcBlock->isExtensible()) { + if (!clone->makeNonExtensible(cx)) + return nullptr; + } + return clone; } diff --git a/js/src/vm/ScopeObject.h b/js/src/vm/ScopeObject.h index 1d9c4a838ed5..6d38295c2177 100644 --- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -715,6 +715,11 @@ class StaticBlockObject : public BlockObject return numVariables() > 0 && !getSlot(RESERVED_SLOTS).isFalse(); } + // Is this the static global lexical scope? + bool isGlobal() { + return !enclosingStaticScope(); + } + /* Frontend-only functions ***********************************************/ /* Initialization functions for above fields. */ @@ -771,6 +776,8 @@ class ClonedBlockObject : public BlockObject static ClonedBlockObject* create(JSContext* cx, Handle block, AbstractFramePtr frame); + static ClonedBlockObject* createGlobal(JSContext* cx, Handle global); + static ClonedBlockObject* createHollowForDebug(JSContext* cx, Handle block); @@ -790,6 +797,17 @@ class ClonedBlockObject : public BlockObject setSlotValue(i, v); } + // Is this the global lexical scope? + bool isGlobal() const { + MOZ_ASSERT_IF(staticBlock().isGlobal(), enclosingScope().is()); + return enclosingScope().is(); + } + + GlobalObject& global() const { + MOZ_ASSERT(isGlobal()); + return enclosingScope().as(); + } + /* Copy in all the unaliased formals and locals. */ void copyUnaliasedValues(AbstractFramePtr frame); @@ -1179,6 +1197,18 @@ IsSyntacticScope(JSObject* scope) !scope->is(); } +inline bool +IsGlobalLexicalScope(JSObject* scope) +{ + return scope->is() && scope->as().isGlobal(); +} + +inline bool +IsStaticGlobalLexicalScope(JSObject* scope) +{ + return scope->is() && scope->as().isGlobal(); +} + inline const Value& ScopeObject::aliasedVar(ScopeCoordinate sc) { diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 3b2a927d6683..665243a7347b 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -1884,8 +1884,10 @@ CloneObject(JSContext* cx, HandleNativeObject selfHostedObject) ? gc::AllocKind::FUNCTION_EXTENDED : selfHostedFunction->getAllocKind(); MOZ_ASSERT(!CanReuseScriptForClone(cx->compartment(), selfHostedFunction, cx->global())); - clone = CloneFunctionAndScript(cx, selfHostedFunction, cx->global(), - /* newStaticScope = */ nullptr, kind); + Rooted globalLexical(cx, &cx->global()->lexicalScope()); + RootedObject staticGlobalLexical(cx, &globalLexical->staticBlock()); + clone = CloneFunctionAndScript(cx, selfHostedFunction, globalLexical, + staticGlobalLexical, kind); // To be able to re-lazify the cloned function, its name in the // self-hosting compartment has to be stored on the clone. if (clone && hasName) @@ -1977,8 +1979,15 @@ JSRuntime::cloneSelfHostedFunctionScript(JSContext* cx, HandlePropertyName name, RootedScript sourceScript(cx, sourceFun->getOrCreateScript(cx)); if (!sourceScript) return false; - MOZ_ASSERT(!sourceScript->enclosingStaticScope()); - if (!CloneScriptIntoFunction(cx, /* enclosingScope = */ nullptr, targetFun, sourceScript)) + + // Assert that there are no intervening scopes between the global scope + // and the self-hosted script. Toplevel lexicals are explicitly forbidden + // by the parser when parsing self-hosted code. The fact they have the + // global lexical scope on the scope chain is for uniformity and engine + // invariants. + MOZ_ASSERT(IsStaticGlobalLexicalScope(sourceScript->enclosingStaticScope())); + Rooted enclosingScope(cx, &cx->global()->lexicalScope().staticBlock()); + if (!CloneScriptIntoFunction(cx, enclosingScope, targetFun, sourceScript)) return false; MOZ_ASSERT(!targetFun->isInterpretedLazy()); diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 57efd8f4487e..94879d6e9cec 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -140,6 +140,7 @@ static inline void AssertDynamicScopeMatchesStaticScope(JSContext* cx, JSScript* script, JSObject* scope) { #ifdef DEBUG + RootedObject originalScope(cx, scope); RootedObject enclosingScope(cx, script->enclosingStaticScope()); for (StaticScopeIter i(enclosingScope); !i.done(); i++) { if (i.type() == StaticScopeIter::NonSyntactic) { @@ -258,7 +259,12 @@ InterpreterFrame::epilogue(JSContext* cx) } if (isGlobalFrame()) { - MOZ_ASSERT(!IsSyntacticScope(scopeChain())); + // Confusingly, global frames may run in non-global scopes (that is, + // not directly under the GlobalObject and its lexical scope). + // + // Gecko often runs global scripts under custom scopes. See users of + // CreateNonSyntacticScopeChain. + MOZ_ASSERT(IsGlobalLexicalScope(scopeChain()) || !IsSyntacticScope(scopeChain())); return; } From 2c1ffa9a18c2a1ab96aa675a466add6fbc14c325 Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Tue, 6 Oct 2015 14:00:29 -0700 Subject: [PATCH 083/228] Bug 589199 - Parse and emit bytecode for global lexicals. (r=efaust) --- js/src/builtin/ModuleObject.cpp | 1 - js/src/builtin/ReflectParse.cpp | 10 +- js/src/frontend/BytecodeCompiler.cpp | 9 +- js/src/frontend/BytecodeEmitter.cpp | 56 ++---- js/src/frontend/FoldConstants.cpp | 7 +- js/src/frontend/FullParseHandler.h | 26 ++- js/src/frontend/NameFunctions.cpp | 1 - js/src/frontend/ParseNode.cpp | 2 - js/src/frontend/ParseNode.h | 4 - js/src/frontend/Parser.cpp | 241 +++++++++++------------ js/src/frontend/Parser.h | 22 ++- js/src/frontend/SyntaxParseHandler.h | 7 +- js/src/jit-test/tests/basic/bug673569.js | 8 +- js/src/jsapi.cpp | 26 ++- js/src/jsfun.cpp | 3 +- js/src/jsscript.cpp | 30 ++- js/src/vm/Interpreter.h | 2 + js/src/vm/Opcodes.h | 48 +++-- js/src/vm/ScopeObject.cpp | 9 + js/src/vm/ScopeObject.h | 8 - 20 files changed, 254 insertions(+), 266 deletions(-) diff --git a/js/src/builtin/ModuleObject.cpp b/js/src/builtin/ModuleObject.cpp index bada98a634e8..1a643cf24120 100644 --- a/js/src/builtin/ModuleObject.cpp +++ b/js/src/builtin/ModuleObject.cpp @@ -640,7 +640,6 @@ ModuleBuilder::processExport(frontend::ParseNode* pn) case PNK_VAR: case PNK_CONST: - case PNK_GLOBALCONST: case PNK_LET: { MOZ_ASSERT(kid->isArity(PN_LIST)); for (ParseNode* var = kid->pn_head; var; var = var->pn_next) { diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp index 8c30db7c3996..0d090b625ce2 100644 --- a/js/src/builtin/ReflectParse.cpp +++ b/js/src/builtin/ReflectParse.cpp @@ -2166,7 +2166,6 @@ ASTSerializer::declaration(ParseNode* pn, MutableHandleValue dst) { MOZ_ASSERT(pn->isKind(PNK_FUNCTION) || pn->isKind(PNK_VAR) || - pn->isKind(PNK_GLOBALCONST) || pn->isKind(PNK_LET) || pn->isKind(PNK_CONST)); @@ -2175,7 +2174,6 @@ ASTSerializer::declaration(ParseNode* pn, MutableHandleValue dst) return function(pn, AST_FUNC_DECL, dst); case PNK_VAR: - case PNK_GLOBALCONST: return variableDeclaration(pn, false, dst); default: @@ -2188,7 +2186,7 @@ bool ASTSerializer::variableDeclaration(ParseNode* pn, bool lexical, MutableHandleValue dst) { MOZ_ASSERT_IF(lexical, pn->isKind(PNK_LET) || pn->isKind(PNK_CONST)); - MOZ_ASSERT_IF(!lexical, pn->isKind(PNK_VAR) || pn->isKind(PNK_GLOBALCONST)); + MOZ_ASSERT_IF(!lexical, pn->isKind(PNK_VAR)); VarDeclKind kind = VARDECL_ERR; // Treat both the toplevel const binding (secretly var-like) and the lexical const @@ -2345,9 +2343,8 @@ ASTSerializer::exportDeclaration(ParseNode* pn, MutableHandleValue dst) case PNK_VAR: case PNK_CONST: - case PNK_GLOBALCONST: case PNK_LET: - if (!variableDeclaration(kid, (kind == PNK_LET || kind == PNK_CONST), &decl)) + if (!variableDeclaration(kid, kind != PNK_VAR, &decl)) return false; break; @@ -2494,7 +2491,7 @@ ASTSerializer::forInit(ParseNode* pn, MutableHandleValue dst) return true; } - return (pn->isKind(PNK_VAR) || pn->isKind(PNK_GLOBALCONST)) + return (pn->isKind(PNK_VAR)) ? variableDeclaration(pn, false, dst) : expression(pn, dst); } @@ -2544,7 +2541,6 @@ ASTSerializer::statement(ParseNode* pn, MutableHandleValue dst) switch (pn->getKind()) { case PNK_FUNCTION: case PNK_VAR: - case PNK_GLOBALCONST: return declaration(pn, dst); case PNK_LETBLOCK: diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index d28303476940..6623743a9860 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -76,6 +76,7 @@ class MOZ_STACK_CLASS BytecodeCompiler bool insideNonGlobalEval = false); bool isEvalCompilationUnit(); bool isNonGlobalEvalCompilationUnit(); + bool isNonSyntacticCompilationUnit(); bool createParseContext(Maybe>& parseContext, SharedContext& globalsc, uint32_t blockScopeDepth = 0); bool saveCallerFun(HandleScript evalCaller, ParseContext& parseContext); @@ -280,7 +281,7 @@ BytecodeCompiler::createEmitter(SharedContext* sharedContext, HandleScript evalC bool BytecodeCompiler::isEvalCompilationUnit() { - return enclosingStaticScope && enclosingStaticScope->is(); + return enclosingStaticScope->is(); } bool @@ -290,6 +291,12 @@ BytecodeCompiler::isNonGlobalEvalCompilationUnit() enclosingStaticScope->as().enclosingScopeForStaticScopeIter(); } +bool +BytecodeCompiler::isNonSyntacticCompilationUnit() +{ + return enclosingStaticScope->is(); +} + bool BytecodeCompiler::createParseContext(Maybe>& parseContext, SharedContext& globalsc, uint32_t blockScopeDepth) diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index b989cb4df7df..088b61e12f75 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -823,7 +823,7 @@ BytecodeEmitter::computeLocalOffset(Handle blockObj) if (StmtInfoBCE* stmt = innermostScopeStmt()) { Rooted outer(cx, stmt->staticScope); for (; outer; outer = outer->enclosingNestedScope()) { - if (outer->is()) { + if (outer->is() && !IsStaticGlobalLexicalScope(outer)) { StaticBlockObject& outerBlock = outer->as(); localOffset = outerBlock.localOffset() + outerBlock.numVariables(); break; @@ -1354,15 +1354,15 @@ BytecodeEmitter::emitVarIncDec(ParseNode* pn) bool BytecodeEmitter::atBodyLevel() const { - // 'eval' scripts are always under an invisible lexical scope, but - // since it is not syntactic, it should still be considered at body - // level. - if (sc->staticScope() && sc->staticScope()->is()) { + // 'eval' and non-syntactic scripts are always under an invisible lexical + // scope, but since it is not syntactic, it should still be considered at + // body level. + if (sc->staticScope()->is()) { bool bl = !innermostStmt()->enclosing; MOZ_ASSERT_IF(bl, innermostStmt()->type == StmtType::BLOCK); MOZ_ASSERT_IF(bl, innermostStmt()->staticScope ->as() - .maybeEnclosingEval() == sc->staticScope()); + .enclosingStaticScope() == sc->staticScope()); return bl; } return !innermostStmt() || sc->isModuleBox(); @@ -1429,7 +1429,6 @@ BytecodeEmitter::isAliasedName(BytecodeEmitter* bceOfDef, ParseNode* pn) */ return script->formalIsAliased(pn->pn_scopecoord.slot()); case Definition::VAR: - case Definition::GLOBALCONST: MOZ_ASSERT_IF(sc->allLocalsAliased(), script->localIsAliased(pn->pn_scopecoord.slot())); return script->localIsAliased(pn->pn_scopecoord.slot()); case Definition::PLACEHOLDER: @@ -1643,14 +1642,13 @@ BytecodeEmitter::tryConvertFreeName(ParseNode* pn) JSOp op; switch (pn->getOp()) { - case JSOP_GETNAME: op = JSOP_GETGNAME; break; - case JSOP_SETNAME: op = strictifySetNameOp(JSOP_SETGNAME); break; - case JSOP_SETCONST: - // Not supported. - return false; + case JSOP_GETNAME: op = JSOP_GETGNAME; break; + case JSOP_SETNAME: op = strictifySetNameOp(JSOP_SETGNAME); break; default: MOZ_CRASH("gname"); } pn->setOp(op); + MOZ_ASSERT_IF(op == JSOP_INITGLEXICAL, + IsStaticGlobalLexicalScope(blockScopeOfDef(pn->resolve()))); return true; } @@ -1704,7 +1702,6 @@ BytecodeEmitter::bindNameToSlotHelper(ParseNode* pn) // Throw an error on attempts to mutate const-declared bindings. switch (op) { case JSOP_GETNAME: - case JSOP_SETCONST: break; default: if (pn->isConst()) { @@ -1789,7 +1786,6 @@ BytecodeEmitter::bindNameToSlotHelper(ParseNode* pn) break; case Definition::VAR: - case Definition::GLOBALCONST: case Definition::CONST: case Definition::LET: switch (op) { @@ -1798,8 +1794,6 @@ BytecodeEmitter::bindNameToSlotHelper(ParseNode* pn) case JSOP_SETNAME: case JSOP_STRICTSETNAME: op = JSOP_SETLOCAL; break; - case JSOP_SETCONST: - op = JSOP_SETLOCAL; break; default: MOZ_CRASH("local"); } break; @@ -2163,7 +2157,6 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) case PNK_VAR: case PNK_CONST: case PNK_LET: - case PNK_GLOBALCONST: MOZ_ASSERT(pn->isArity(PN_LIST)); *answer = true; return true; @@ -3001,8 +2994,7 @@ BytecodeEmitter::enterBlockScope(StmtInfoBCE* stmtInfo, ObjectBox* objbox, JSOp { // This is so terrible. The eval body-level lexical scope needs to be // emitted in the prologue so DEFFUN can pick up the right scope chain. - bool isEvalBodyLexicalScope = sc->staticScope() && - sc->staticScope()->is() && + bool isEvalBodyLexicalScope = sc->staticScope()->is() && !innermostStmt(); if (isEvalBodyLexicalScope) { MOZ_ASSERT(code().length() == 0); @@ -3704,7 +3696,7 @@ BytecodeEmitter::emitDestructuringLHS(ParseNode* target, VarEmitOption emitOptio case JSOP_STRICTSETNAME: case JSOP_SETGNAME: case JSOP_STRICTSETGNAME: - case JSOP_SETCONST: { + case JSOP_INITGLEXICAL: { // This is like ordinary assignment, but with one difference. // // In `a = b`, we first determine a binding for `a` (using @@ -3719,7 +3711,9 @@ BytecodeEmitter::emitDestructuringLHS(ParseNode* target, VarEmitOption emitOptio if (!makeAtomIndex(target->pn_atom, &atomIndex)) return false; - if (!target->isOp(JSOP_SETCONST)) { + // INITGLEXICAL always initializes a binding on the global + // lexical scope and does not need a BINDGNAME. + if (!target->isOp(JSOP_INITGLEXICAL)) { bool global = target->isOp(JSOP_SETGNAME) || target->isOp(JSOP_STRICTSETGNAME); JSOp bindOp = global ? JSOP_BINDGNAME : JSOP_BINDNAME; if (!emitIndex32(bindOp, atomIndex)) @@ -4341,7 +4335,7 @@ BytecodeEmitter::emitVariables(ParseNode* pn, VarEmitOption emitOption, bool isL if (!emitTree(pn3)) return false; emittingForInit = oldEmittingForInit; - } else if (op == JSOP_INITLEXICAL || isLetExpr) { + } else if (op == JSOP_INITLEXICAL || op == JSOP_INITGLEXICAL || isLetExpr) { // 'let' bindings cannot be used before they are // initialized. JSOP_INITLEXICAL distinguishes the binding site. MOZ_ASSERT(emitOption != DefineVars); @@ -7382,13 +7376,6 @@ BytecodeEmitter::emitDefaultsAndDestructuring(ParseNode* pn) bool BytecodeEmitter::emitLexicalInitialization(ParseNode* pn, JSOp globalDefOp) { - /* - * This function is significantly more complicated than it needs to be. - * In fact, it shouldn't exist at all. This should all be a - * JSOP_INITLEXIAL. Unfortunately, toplevel lexicals are broken, and - * are emitted as vars :(. As such, we have to do these ministrations to - * to make sure that all works properly. - */ MOZ_ASSERT(pn->isKind(PNK_NAME)); if (!bindNameToSlot(pn)) @@ -7398,14 +7385,6 @@ BytecodeEmitter::emitLexicalInitialization(ParseNode* pn, JSOp globalDefOp) if (!maybeEmitVarDecl(globalDefOp, pn, &atomIndex)) return false; - if (pn->getOp() != JSOP_INITLEXICAL) { - bool global = IsGlobalOp(pn->getOp()); - if (!emitIndex32(global ? JSOP_BINDGNAME : JSOP_BINDNAME, atomIndex)) - return false; - if (!emit1(JSOP_SWAP)) - return false; - } - if (!pn->pn_scopecoord.isFree()) { if (!emitVarOp(pn, pn->getOp())) return false; @@ -7509,7 +7488,7 @@ BytecodeEmitter::emitClass(ParseNode* pn) ParseNode* outerName = names->outerBinding(); if (outerName) { - if (!emitLexicalInitialization(outerName, JSOP_DEFVAR)) + if (!emitLexicalInitialization(outerName, JSOP_DEFLET)) return false; // Only class statements make outer bindings, and they do not leave // themselves on the stack. @@ -7675,7 +7654,6 @@ BytecodeEmitter::emitTree(ParseNode* pn) break; case PNK_VAR: - case PNK_GLOBALCONST: if (!emitVariables(pn, InitializeVars)) return false; break; diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp index 003ed0b58334..c46b07b36eed 100644 --- a/js/src/frontend/FoldConstants.cpp +++ b/js/src/frontend/FoldConstants.cpp @@ -75,7 +75,7 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result) // Non-global lexical declarations are block-scoped (ergo not hoistable). // (Global lexical declarations, in addition to being irrelevant here as // ContainsHoistedDeclaration is only used on the arms of an |if| - // statement, are handled by PNK_GLOBALCONST and PNK_VAR.) + // statement, are handled by PNK_VAR.) case PNK_LET: case PNK_CONST: MOZ_ASSERT(node->isArity(PN_LIST)); @@ -417,10 +417,6 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result) MOZ_CRASH("ContainsHoistedDeclaration should have indicated false on " "some parent node without recurring to test this node"); - case PNK_GLOBALCONST: - MOZ_CRASH("ContainsHoistedDeclaration is only called on nested nodes where " - "globalconst nodes should never have been generated"); - case PNK_LIMIT: // invalid sentinel value MOZ_CRASH("unexpected PNK_LIMIT in node"); } @@ -1837,7 +1833,6 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser& parser, bo case PNK_TEMPLATE_STRING_LIST: case PNK_VAR: case PNK_CONST: - case PNK_GLOBALCONST: case PNK_LET: case PNK_ARGSBODY: case PNK_CALLSITEOBJ: diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index db069cdfd490..c05e8f9bfef0 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -720,6 +720,7 @@ class FullParseHandler } inline bool finishInitializerAssignment(ParseNode* pn, ParseNode* init, JSOp op); + inline void setLexicalDeclarationOp(ParseNode* pn, JSOp op); void setBeginPosition(ParseNode* pn, ParseNode* oth) { setBeginPosition(pn, oth->pn_pos.begin); @@ -752,8 +753,7 @@ class FullParseHandler return new_(kind, op, TokenPos(begin, begin + 1)); } ParseNode* newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) { - MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET || - kind == PNK_GLOBALCONST); + MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET); return new_(kind, op, pos()); } @@ -763,8 +763,7 @@ class FullParseHandler return new_(kind, op, kid); } ParseNode* newDeclarationList(ParseNodeKind kind, ParseNode* kid, JSOp op = JSOP_NOP) { - MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET || - kind == PNK_GLOBALCONST); + MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET); return new_(kind, op, kid); } @@ -993,12 +992,8 @@ FullParseHandler::finishInitializerAssignment(ParseNode* pn, ParseNode* init, JS pn->pn_expr = init; } - if (op == JSOP_INITLEXICAL) - pn->setOp(op); - else if (pn->pn_dflags & PND_BOUND) + if (pn->pn_dflags & PND_BOUND) pn->setOp(JSOP_SETLOCAL); - else if (op == JSOP_DEFCONST) - pn->setOp(JSOP_SETCONST); else pn->setOp(JSOP_SETNAME); @@ -1009,6 +1004,19 @@ FullParseHandler::finishInitializerAssignment(ParseNode* pn, ParseNode* init, JS return true; } +inline void +FullParseHandler::setLexicalDeclarationOp(ParseNode* pn, JSOp op) +{ + if (op == JSOP_DEFLET || op == JSOP_DEFCONST) { + // Subtlety here. Lexical definitions that are PND_BOUND but whose + // scope coordinates are free are global lexicals. They cannot use + // scope coordinate lookup because we rely on being able to clone + // scripts to run on multiple globals. However, they always go on the + // global lexical scope, so in that sense they are bound. + pn->setOp(pn->pn_scopecoord.isFree() ? JSOP_INITGLEXICAL : JSOP_INITLEXICAL); + } +} + inline ParseNode* FullParseHandler::makeAssignment(ParseNode* pn, ParseNode* rhs) { diff --git a/js/src/frontend/NameFunctions.cpp b/js/src/frontend/NameFunctions.cpp index 9c5fae0b0839..388ddd9802cb 100644 --- a/js/src/frontend/NameFunctions.cpp +++ b/js/src/frontend/NameFunctions.cpp @@ -682,7 +682,6 @@ class NameResolver case PNK_VAR: case PNK_CONST: case PNK_LET: - case PNK_GLOBALCONST: MOZ_ASSERT(cur->isArity(PN_LIST)); for (ParseNode* element = cur->pn_head; element; element = element->pn_next) { if (!resolve(element, prefix)) diff --git a/js/src/frontend/ParseNode.cpp b/js/src/frontend/ParseNode.cpp index 4ab4aeff20f0..3458d3182aeb 100644 --- a/js/src/frontend/ParseNode.cpp +++ b/js/src/frontend/ParseNode.cpp @@ -497,7 +497,6 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack) case PNK_CALLSITEOBJ: case PNK_VAR: case PNK_CONST: - case PNK_GLOBALCONST: case PNK_LET: case PNK_CATCHLIST: case PNK_STATEMENTLIST: @@ -656,7 +655,6 @@ Definition::kindString(Kind kind) "", js_var_str, js_const_str, - js_const_str, js_let_str, "argument", js_function_str, diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index b54f8accf933..c7eb43c3cf32 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -131,7 +131,6 @@ class PackedScopeCoordinate F(CONTINUE) \ F(VAR) \ F(CONST) \ - F(GLOBALCONST) \ F(WITH) \ F(RETURN) \ F(NEW) \ @@ -1571,7 +1570,6 @@ struct Definition : public ParseNode enum Kind { MISSING = 0, VAR, - GLOBALCONST, CONST, LET, ARG, @@ -1601,8 +1599,6 @@ struct Definition : public ParseNode return IMPORT; if (isLexical()) return isConst() ? CONST : LET; - if (isConst()) - return GLOBALCONST; return VAR; } }; diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 38f18d367c78..e563c9f1c00a 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -241,7 +241,6 @@ ParseContext::define(TokenStream& ts, return false; break; - case Definition::GLOBALCONST: case Definition::VAR: if (!sc->isGlobalContext()) { dn->setOp((js_CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETLOCAL : JSOP_GETLOCAL); @@ -262,7 +261,8 @@ ParseContext::define(TokenStream& ts, case Definition::LET: case Definition::CONST: - dn->setOp(JSOP_INITLEXICAL); + // See FullParseHandler::setLexicalDeclarationOp. + dn->setOp(dn->pn_scopecoord.isFree() ? JSOP_INITGLEXICAL : JSOP_INITLEXICAL); dn->pn_dflags |= (PND_LEXICAL | PND_BOUND); if (atModuleLevel()) dn->pn_dflags |= PND_CLOSED; @@ -394,7 +394,6 @@ AppendPackedBindings(const ParseContext* pc, const DeclVector& vec kind = Binding::VARIABLE; break; case Definition::CONST: - case Definition::GLOBALCONST: kind = Binding::CONSTANT; break; case Definition::ARG: @@ -780,8 +779,9 @@ Parser::parse() * an object lock before it finishes generating bytecode into a script * protected from the GC by a root or a stack frame reference. */ + Rooted staticLexical(context, &context->global()->lexicalScope().staticBlock()); Directives directives(options().strictOption); - GlobalSharedContext globalsc(context, /* staticScope = */ nullptr, directives, + GlobalSharedContext globalsc(context, staticLexical, directives, options().extraWarningsOption); ParseContext globalpc(this, /* parent = */ nullptr, ParseHandler::null(), &globalsc, /* newDirectives = */ nullptr, @@ -1316,17 +1316,17 @@ struct BindData : kind_(Uninitialized), nameNode_(ParseHandler::null()), letData_(cx) {} - void initLexical(VarContext varContext, StaticBlockObject* blockObj, unsigned overflow, - bool isConst = false) + void initLexical(VarContext varContext, JSOp op, StaticBlockObject* blockObj, + unsigned overflow) { - init(LexicalBinding, JSOP_INITLEXICAL, isConst); + init(LexicalBinding, op, op == JSOP_DEFCONST); letData_.varContext = varContext; letData_.blockObj = blockObj; letData_.overflow = overflow; } - void initVarOrGlobalConst(JSOp op) { - init(VarBinding, op, op == JSOP_DEFCONST); + void initVar(JSOp op) { + init(VarBinding, op, false); } void initDestructuring(JSOp op) { @@ -1365,7 +1365,7 @@ struct BindData case LexicalBinding: return Parser::bindLexical(this, name, parser); case VarBinding: - return Parser::bindVarOrGlobalConst(this, name, parser); + return Parser::bindVar(this, name, parser); case DestructuringBinding: return Parser::bindDestructuringArg(this, name, parser); default: @@ -2084,8 +2084,7 @@ Parser::checkFunctionDefinition(HandlePropertyName funName, MOZ_ASSERT(!dn->isUsed()); MOZ_ASSERT(dn->isDefn()); - bool throwRedeclarationError = dn->kind() == Definition::GLOBALCONST || - dn->kind() == Definition::CONST || + bool throwRedeclarationError = dn->kind() == Definition::CONST || dn->kind() == Definition::LET; if (options().extraWarningsOption || throwRedeclarationError) { JSAutoByteString name; @@ -2317,10 +2316,7 @@ Parser::checkFunctionDefinition(HandlePropertyName funName, * function (thereby avoiding JSOP_DEFFUN and dynamic name lookup). */ if (DefinitionNode dn = pc->decls().lookupFirst(funName)) { - if (dn == Definition::GLOBALCONST || - dn == Definition::CONST || - dn == Definition::LET) - { + if (dn == Definition::CONST || dn == Definition::LET) { JSAutoByteString name; if (!AtomToPrintableString(context, funName, &name) || !report(ParseError, false, null(), JSMSG_REDECLARED_VAR, @@ -3267,32 +3263,38 @@ Parser::bindLexical(BindData* data, ExclusiveContext* cx = parser->context; Rooted blockObj(cx, data->letData().blockObj); - unsigned index; + uint32_t index; if (blockObj) { - index = blockObj->numVariables(); - if (index >= StaticBlockObject::LOCAL_INDEX_LIMIT) { - parser->report(ParseError, false, pn, data->letData().overflow); - return false; + // Leave the scope coordinate free on global lexicals. + // + // For block-level lets, assign block-local index to pn->pn_scopecoord + // right away. The emitter will adjust the node's slot based on its + // stack depth model -- and, for global and eval code, + // js::frontend::CompileScript will adjust the slot again to include + // script->nfixed and body-level lets. + // + // XXXshu: I should like to optimize global lexicals, but we rely on + // being able to clone JSScripts to run on multiple globals and to be + // able to parse scripts off-thread in a different compartment. + if (!blockObj->isGlobal()) { + index = blockObj->numVariables(); + if (index >= StaticBlockObject::LOCAL_INDEX_LIMIT) { + parser->report(ParseError, false, pn, data->letData().overflow); + return false; + } + if (!pn->pn_scopecoord.setSlot(parser->tokenStream, index)) + return false; } - } else { - // If we don't have a block object, we are parsing a body-level let, - // in which case we use a bogus index. See comment block below in - // setting the pn_scopecoord for explanation on how it gets adjusted. + } else if (!pc->sc->isGlobalContext()) { + // If we don't have a block object and are parsing a function + // body-level let, use a bogus index. It is adjusted when creating the + // function's Bindings. See ParseContext::generateFunctionBindings and + // AppendPackedBindings. index = 0; + if (!pn->pn_scopecoord.setSlot(parser->tokenStream, index)) + return false; } - // For block-level lets, assign block-local index to pn->pn_scopecoord - // right away. The emitter will adjust the node's slot based on its - // stack depth model -- and, for global and eval code, - // js::frontend::CompileScript will adjust the slot again to include - // script->nfixed and body-level lets. - // - // For body-level lets, the index is bogus at this point and is adjusted - // when creating Bindings. See ParseContext::generateBindings and - // AppendPackedBindings. - if (!pn->pn_scopecoord.setSlot(parser->tokenStream, index)) - return false; - Definition::Kind bindingKind; if (pn->isImport()) bindingKind = Definition::IMPORT; @@ -3315,24 +3317,26 @@ Parser::bindLexical(BindData* data, } if (blockObj) { - bool redeclared; - RootedId id(cx, NameToId(name)); - RootedShape shape(cx, StaticBlockObject::addVar(cx, blockObj, id, - data->isConst(), index, &redeclared)); - if (!shape) { - if (redeclared) { - // The only way to be redeclared without a previous definition is if we're in a - // comma separated list in a DontHoistVars block, so a let block of for header. In - // that case, we must be redeclaring the same type of definition as we're trying to - // make. - Definition::Kind dnKind = dn ? dn->kind() : bindingKind; - parser->reportRedeclaration(pn, dnKind, name); + if (!blockObj->isGlobal()) { + bool redeclared; + RootedId id(cx, NameToId(name)); + RootedShape shape(cx, StaticBlockObject::addVar(cx, blockObj, id, + data->isConst(), index, &redeclared)); + if (!shape) { + if (redeclared) { + // The only way to be redeclared without a previous definition is if we're in a + // comma separated list in a DontHoistVars block, so a let block of for header. In + // that case, we must be redeclaring the same type of definition as we're trying to + // make. + Definition::Kind dnKind = dn ? dn->kind() : bindingKind; + parser->reportRedeclaration(pn, dnKind, name); + } + return false; } - return false; - } - /* Store pn in the static block object. */ - blockObj->setDefinitionParseNode(index, reinterpret_cast(pn)); + /* Store pn in the static block object. */ + blockObj->setDefinitionParseNode(index, reinterpret_cast(pn)); + } } else { // Body-level lets are hoisted and need to have been defined via // pc->define above. @@ -3491,13 +3495,12 @@ OuterLet(ParseContext* pc, StmtInfoPC* stmt, HandleAtom atom) template /* static */ bool -Parser::bindVarOrGlobalConst(BindData* data, - HandlePropertyName name, Parser* parser) +Parser::bindVar(BindData* data, + HandlePropertyName name, Parser* parser) { ExclusiveContext* cx = parser->context; ParseContext* pc = parser->pc; Node pn = data->nameNode(); - bool isConstDecl = data->op() == JSOP_DEFCONST; /* Default best op for pn is JSOP_GETNAME; we'll try to improve below. */ parser->handler.setOp(pn, JSOP_GETNAME); @@ -3530,10 +3533,8 @@ Parser::bindVarOrGlobalConst(BindData* data, DefinitionList::Range defs = pc->decls().lookupMulti(name); MOZ_ASSERT_IF(stmt, !defs.empty()); - if (defs.empty()) { - return pc->define(parser->tokenStream, name, pn, - isConstDecl ? Definition::GLOBALCONST : Definition::VAR); - } + if (defs.empty()) + return pc->define(parser->tokenStream, name, pn, Definition::VAR); /* * There was a previous declaration with the same name. The standard @@ -3548,19 +3549,12 @@ Parser::bindVarOrGlobalConst(BindData* data, JSAutoByteString bytes; if (!AtomToPrintableString(cx, name, &bytes)) return false; - - if (isConstDecl) { - parser->report(ParseError, false, pn, JSMSG_REDECLARED_PARAM, bytes.ptr()); - return false; - } if (!parser->report(ParseExtraWarning, false, pn, JSMSG_VAR_HIDES_ARG, bytes.ptr())) return false; } else { bool inCatchBody = (stmt && stmt->type == StmtType::CATCH); - bool error = (isConstDecl || - dn_kind == Definition::IMPORT || + bool error = (dn_kind == Definition::IMPORT || dn_kind == Definition::CONST || - dn_kind == Definition::GLOBALCONST || (dn_kind == Definition::LET && (!inCatchBody || OuterLet(pc, stmt, name)))); @@ -3681,12 +3675,10 @@ Parser::bindInitialized(BindData* data, Pars * Select the appropriate name-setting opcode, respecting eager selection * done by the data->bind function. */ - if (data->op() == JSOP_INITLEXICAL) - pn->setOp(JSOP_INITLEXICAL); + if (data->op() == JSOP_DEFLET || data->op() == JSOP_DEFCONST) + pn->setOp(pn->pn_scopecoord.isFree() ? JSOP_INITGLEXICAL : JSOP_INITLEXICAL); else if (pn->pn_dflags & PND_BOUND) pn->setOp(JSOP_SETLOCAL); - else if (data->op() == JSOP_DEFCONST) - pn->setOp(JSOP_SETCONST); else pn->setOp(JSOP_SETNAME); @@ -4012,6 +4004,9 @@ Parser::deprecatedLetBlock(YieldHandling yieldHandling) RootedStaticBlockObject blockObj(context, StaticBlockObject::create(context)); if (!blockObj) return null(); + // Initialize the enclosing scope manually for the call to |variables| + // below. + blockObj->initEnclosingScopeFromParser(pc->innermostStaticScope()); uint32_t begin = pos().begin; @@ -4106,14 +4101,7 @@ Parser::variables(YieldHandling yieldHandling, ForInitLocation location, bool* psimple, StaticBlockObject* blockObj, VarContext varContext) { - /* - * The four options here are: - * - PNK_VAR: We're parsing var declarations. - * - PNK_CONST: We're parsing const declarations. - * - PNK_GLOBALCONST: We're parsing const declarations at toplevel (see bug 589119). - * - PNK_LET: We are parsing a let declaration. - */ - MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET || kind == PNK_GLOBALCONST); + MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET); /* * The simple flag is set if the declaration has the form 'var x', with @@ -4121,28 +4109,23 @@ Parser::variables(YieldHandling yieldHandling, */ MOZ_ASSERT_IF(psimple, *psimple); - JSOp op = JSOP_NOP; - if (kind == PNK_VAR) - op = JSOP_DEFVAR; - else if (kind == PNK_GLOBALCONST) - op = JSOP_DEFCONST; + JSOp op; + switch (kind) { + case PNK_VAR: op = JSOP_DEFVAR; break; + case PNK_CONST: op = JSOP_DEFCONST; break; + case PNK_LET: op = JSOP_DEFLET; break; + default: MOZ_CRASH("unknown variable kind"); + } Node pn = handler.newDeclarationList(kind, op); if (!pn) return null(); - /* - * SpiderMonkey const is really "write once per initialization evaluation" - * var, whereas let is block scoped. ES-Harmony wants block-scoped const so - * this code will change soon. - */ BindData data(context); - if (kind == PNK_VAR || kind == PNK_GLOBALCONST) { - data.initVarOrGlobalConst(op); - } else { - data.initLexical(varContext, blockObj, JSMSG_TOO_MANY_LOCALS, - /* isConst = */ kind == PNK_CONST); - } + if (kind == PNK_VAR) + data.initVar(op); + else + data.initLexical(varContext, op, blockObj, JSMSG_TOO_MANY_LOCALS); bool first = true; Node pn2; @@ -4228,7 +4211,7 @@ Parser::variables(YieldHandling yieldHandling, } RootedPropertyName name(context, tokenStream.currentName()); - pn2 = newBindingNode(name, kind == PNK_VAR || kind == PNK_GLOBALCONST, varContext); + pn2 = newBindingNode(name, kind == PNK_VAR, varContext); if (!pn2) return null(); if (data.isConst()) @@ -4309,6 +4292,7 @@ Parser::variables(YieldHandling yieldHandling, } } + handler.setLexicalDeclarationOp(pn2, data.op()); handler.setEndPosition(pn, pn2); } while (false); @@ -4348,14 +4332,9 @@ Parser::checkAndPrepareLexical(bool isConst, const TokenPos& e MOZ_ASSERT(pc->atBodyLevel()); /* - * When bug 589199 is fixed, let variables will be stored in - * the slots of a new scope chain object, encountered just - * before the global object in the overall chain. This extra - * object is present in the scope chain for all code in that - * global, including self-hosted code. But self-hosted code - * must be usable against *any* global object, including ones - * with other let variables -- variables possibly placed in - * conflicting slots. Forbid top-level let declarations to + * Self-hosted code must be usable against *any* global object, + * including ones with other let variables -- variables possibly + * placed in conflicting slots. Forbid top-level let declarations to * prevent such conflicts from ever occurring. */ bool isGlobal = !pc->sc->isFunctionBox() && stmt == pc->innermostScopeStmt(); @@ -4409,8 +4388,12 @@ Parser::checkAndPrepareLexical(bool isConst, const TokenPos& e static StaticBlockObject* CurrentLexicalStaticBlock(ParseContext* pc) { - return !pc->innermostStmt() ? nullptr : - &pc->innermostStmt()->staticScope->as(); + if (pc->innermostStaticScope()->is()) + return &pc->innermostStaticScope()->as(); + MOZ_ASSERT(pc->atBodyLevel() && + (!pc->sc->isGlobalContext() || + HasNonSyntacticStaticScopeChain(pc->innermostStaticScope()))); + return nullptr; } template <> @@ -4418,16 +4401,12 @@ ParseNode* Parser::makeInitializedLexicalBinding(HandlePropertyName name, bool isConst, const TokenPos& pos) { - // Handle the silliness of global and body level lexical decls. BindData data(context); - if (pc->atGlobalLevel()) { - data.initVarOrGlobalConst(isConst ? JSOP_DEFCONST : JSOP_DEFVAR); - } else { - if (!checkAndPrepareLexical(isConst, pos)) - return null(); - data.initLexical(HoistVars, CurrentLexicalStaticBlock(pc), JSMSG_TOO_MANY_LOCALS, isConst); - } - ParseNode* dn = newBindingNode(name, pc->atGlobalLevel()); + if (!checkAndPrepareLexical(isConst, pos)) + return null(); + data.initLexical(HoistVars, isConst ? JSOP_DEFCONST : JSOP_DEFLET, + CurrentLexicalStaticBlock(pc), JSMSG_TOO_MANY_LOCALS); + ParseNode* dn = newBindingNode(name, false); if (!dn) return null(); handler.setPosition(dn, pos); @@ -4457,16 +4436,8 @@ Parser::lexicalDeclaration(YieldHandling yieldHandling, bool i * requires that uninitialized lets throw ReferenceError on use. * * See 8.1.1.1.6 and the note in 13.2.1. - * - * FIXME global-level lets are still considered vars until - * other bugs are fixed. */ - ParseNodeKind kind = PNK_LET; - if (pc->atGlobalLevel()) - kind = isConst ? PNK_GLOBALCONST : PNK_VAR; - else if (isConst) - kind = PNK_CONST; - + ParseNodeKind kind = isConst ? PNK_CONST : PNK_LET; ParseNode* pn = variables(yieldHandling, kind, NotInForInit, nullptr, CurrentLexicalStaticBlock(pc), HoistVars); if (!pn) @@ -4532,7 +4503,7 @@ Parser::newBoundImportForCurrentName() importNode->pn_dflags |= PND_CONST | PND_IMPORT; BindData data(context); - data.initLexical(HoistVars, nullptr, JSMSG_TOO_MANY_LOCALS); + data.initLexical(HoistVars, JSOP_DEFLET, nullptr, JSMSG_TOO_MANY_LOCALS); handler.setPosition(importNode, pos()); if (!bindUninitialized(&data, importNode)) return null(); @@ -5271,6 +5242,9 @@ Parser::forStatement(YieldHandling yieldHandling) blockObj = StaticBlockObject::create(context); if (!blockObj) return null(); + // Initialize the enclosing scope manually for the call to + // |variables| below. + blockObj->initEnclosingScopeFromParser(pc->innermostStaticScope()); pn1 = variables(yieldHandling, constDecl ? PNK_CONST : PNK_LET, InForInit, nullptr, blockObj, DontHoistVars); } else { @@ -5287,7 +5261,7 @@ Parser::forStatement(YieldHandling yieldHandling) } MOZ_ASSERT_IF(isForDecl, pn1->isArity(PN_LIST)); - MOZ_ASSERT(!!blockObj == (isForDecl && pn1->isOp(JSOP_NOP))); + MOZ_ASSERT(!!blockObj == (isForDecl && (pn1->isOp(JSOP_DEFLET) || pn1->isOp(JSOP_DEFCONST)))); // All forms of for-loop (for(;;), for-in, for-of) generate an implicit // block to store any lexical variables declared by the loop-head. We @@ -6298,7 +6272,7 @@ Parser::tryStatement(YieldHandling yieldHandling) * scoped, not a property of a new Object instance. This is * an intentional change that anticipates ECMA Ed. 4. */ - data.initLexical(HoistVars, + data.initLexical(HoistVars, JSOP_DEFLET, &stmtInfo->staticScope->template as(), JSMSG_TOO_MANY_CATCH_VARS); MOZ_ASSERT(data.letData().blockObj); @@ -7798,7 +7772,7 @@ Parser::legacyComprehensionTail(ParseNode* bodyExpr, unsigned MOZ_ASSERT(pc->innermostScopeStmt() && pc->innermostScopeStmt()->staticScope == pn->pn_objbox->object); - data.initLexical(HoistVars, + data.initLexical(HoistVars, JSOP_DEFLET, &pc->innermostScopeStmt()->staticScope->as(), JSMSG_ARRAY_INIT_TOO_BIG); @@ -7916,7 +7890,7 @@ Parser::legacyComprehensionTail(ParseNode* bodyExpr, unsigned * These are lets to tell the bytecode emitter to emit initialization * code for the temporal dead zone. */ - ParseNode* lets = handler.newList(PNK_LET, pn3); + ParseNode* lets = handler.newDeclarationList(PNK_LET, pn3, JSOP_DEFLET); if (!lets) return null(); lets->pn_xflags |= PNX_POPVAR; @@ -8227,10 +8201,15 @@ Parser::comprehensionFor(GeneratorKind comprehensionKind) AutoPushStmtInfoPC stmtInfo(*this, StmtType::BLOCK); BindData data(context); + RootedStaticBlockObject blockObj(context, StaticBlockObject::create(context)); if (!blockObj) return null(); - data.initLexical(DontHoistVars, blockObj, JSMSG_TOO_MANY_LOCALS); + // Initialize the enclosing scope manually for the call to |bind| + // below, which is before the call to |pushLetScope|. + blockObj->initEnclosingScopeFromParser(pc->innermostStaticScope()); + + data.initLexical(DontHoistVars, JSOP_DEFLET, blockObj, JSMSG_TOO_MANY_LOCALS); Node decls = handler.newList(PNK_LET, lhs); if (!decls) return null(); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index b929ec50447e..a8d3bebab5cb 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -301,15 +301,15 @@ struct MOZ_STACK_CLASS ParseContext : public GenericParseContext // if (cond) { function f3() { if (cond) { function f4() { } } } } // bool atBodyLevel() { - // 'eval' scripts are always under an invisible lexical scope, but - // since it is not syntactic, it should still be considered at body - // level. - if (sc->staticScope() && sc->staticScope()->is()) { + // 'eval' and non-syntactic scripts are always under an invisible + // lexical scope, but since it is not syntactic, it should still be + // considered at body level. + if (sc->staticScope()->is()) { bool bl = !innermostStmt()->enclosing; MOZ_ASSERT_IF(bl, innermostStmt()->type == StmtType::BLOCK); MOZ_ASSERT_IF(bl, innermostStmt()->staticScope ->template as() - .maybeEnclosingEval() == sc->staticScope()); + .enclosingStaticScope() == sc->staticScope()); return bl; } return !innermostStmt(); @@ -578,9 +578,11 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter bool maybeParseDirective(Node list, Node pn, bool* cont); - // Parse the body of an eval. It is distinguished from global scripts in - // that in ES6, per 18.2.1.1 steps 9 and 10, all eval scripts are executed - // under a fresh lexical scope. + // Parse the body of an eval. + // + // Eval scripts are distinguished from global scripts in that in ES6, per + // 18.2.1.1 steps 9 and 10, all eval scripts are executed under a fresh + // lexical scope. Node evalBody(); // Parse a module. @@ -850,8 +852,8 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter HandlePropertyName name, Parser* parser); static bool - bindVarOrGlobalConst(BindData* data, - HandlePropertyName name, Parser* parser); + bindVar(BindData* data, + HandlePropertyName name, Parser* parser); static Node null() { return ParseHandler::null(); } diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index da8b1841c5ed..c3a2d2de3eec 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -349,6 +349,7 @@ class SyntaxParseHandler } bool finishInitializerAssignment(Node pn, Node init, JSOp op) { return true; } + void setLexicalDeclarationOp(Node pn, JSOp op) {} void setBeginPosition(Node pn, Node oth) {} void setBeginPosition(Node pn, uint32_t begin) {} @@ -371,8 +372,7 @@ class SyntaxParseHandler return NodeGeneric; } Node newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) { - MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET || - kind == PNK_GLOBALCONST); + MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET); return kind == PNK_VAR ? NodeHoistableDeclaration : NodeGeneric; } Node newList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) { @@ -380,8 +380,7 @@ class SyntaxParseHandler return NodeGeneric; } Node newDeclarationList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) { - MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET || - kind == PNK_GLOBALCONST); + MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET); return kind == PNK_VAR ? NodeHoistableDeclaration : NodeGeneric; } diff --git a/js/src/jit-test/tests/basic/bug673569.js b/js/src/jit-test/tests/basic/bug673569.js index 11ecdef7ee79..05f031d9ce3a 100644 --- a/js/src/jit-test/tests/basic/bug673569.js +++ b/js/src/jit-test/tests/basic/bug673569.js @@ -1,11 +1,5 @@ function qualified_tests(prefix) { - let scope = evalReturningScope(prefix + "let x = 1"); - assertEq(scope.x, 1); - - scope = evalReturningScope(prefix + "var x = 1"); - assertEq(scope.x, 1); - - scope = evalReturningScope(prefix + "const x = 1"); + let scope = evalReturningScope(prefix + "var x = 1"); assertEq(scope.x, 1); } diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 29cc5a4b8a77..a9bfc3db8189 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3470,20 +3470,28 @@ IsFunctionCloneable(HandleFunction fun) // If a function was compiled to be lexically nested inside some other // script, we cannot clone it without breaking the compiler's assumptions. if (JSObject* scope = fun->nonLazyScript()->enclosingStaticScope()) { - // If the script already deals with a non-syntactic scope, we can clone - // it. - if (scope->is()) - return true; - // If the script is directly under the global scope, we can clone it. if (IsStaticGlobalLexicalScope(scope)) return true; - // If the script is an indirect eval that is immediately scoped under - // the global, we can clone it. + // 'eval' and non-syntactic scopes are always scoped immediately under + // a non-extensible lexical scope. if (scope->is()) { - if (StaticEvalObject* staticEval = scope->as().maybeEnclosingEval()) - return !staticEval->isDirect(); + StaticBlockObject& block = scope->as(); + if (block.needsClone()) + return false; + + JSObject* enclosing = block.enclosingStaticScope(); + + // If the script is an indirect eval that is immediately scoped + // under the global, we can clone it. + if (enclosing->is()) + return !enclosing->as().isDirect(); + + // If the script already deals with a non-syntactic scope, we can + // clone it. + if (enclosing->is()) + return true; } // Any other enclosing static scope (e.g., function, block) cannot be diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 080f7b82e41f..a0c3f62f2398 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -590,8 +590,9 @@ js::XDRInterpretedFunction(XDRState* xdr, HandleObject enclosingScope, Han gc::AllocKind allocKind = gc::AllocKind::FUNCTION; if (uint16_t(flagsword) & JSFunction::EXTENDED) allocKind = gc::AllocKind::FUNCTION_EXTENDED; + RootedObject globalLexical(cx, &cx->global()->lexicalScope()); fun = NewFunctionWithProto(cx, nullptr, 0, JSFunction::INTERPRETED, - /* enclosingDynamicScope = */ nullptr, nullptr, proto, + globalLexical, nullptr, proto, allocKind, TenuredObject); if (!fun) return false; diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index dcbfb1f0680f..426216bb7287 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -990,10 +990,14 @@ js::XDRScript(XDRState* xdr, HandleObject enclosingScopeArg, HandleScript uint32_t enclosingStaticScopeIndex = 0; if (mode == XDR_ENCODE) { NestedScopeObject& scope = (*objp)->as(); - if (NestedScopeObject* enclosing = scope.enclosingNestedScope()) - enclosingStaticScopeIndex = FindScopeObjectIndex(script, *enclosing); - else + if (NestedScopeObject* enclosing = scope.enclosingNestedScope()) { + if (IsStaticGlobalLexicalScope(enclosing)) + enclosingStaticScopeIndex = UINT32_MAX; + else + enclosingStaticScopeIndex = FindScopeObjectIndex(script, *enclosing); + } else { enclosingStaticScopeIndex = UINT32_MAX; + } } if (!xdr->codeUint32(&enclosingStaticScopeIndex)) return false; @@ -1056,8 +1060,12 @@ js::XDRScript(XDRState* xdr, HandleObject enclosingScopeArg, HandleScript MOZ_ASSERT_IF(ssi.done() || ssi.type() != StaticScopeIter::Function, !fun); funEnclosingScopeIndex = UINT32_MAX; } else if (ssi.type() == StaticScopeIter::Block) { - funEnclosingScopeIndex = FindScopeObjectIndex(script, ssi.block()); - MOZ_ASSERT(funEnclosingScopeIndex < i); + if (ssi.block().isGlobal()) { + funEnclosingScopeIndex = UINT32_MAX; + } else { + funEnclosingScopeIndex = FindScopeObjectIndex(script, ssi.block()); + MOZ_ASSERT(funEnclosingScopeIndex < i); + } } else { funEnclosingScopeIndex = FindScopeObjectIndex(script, ssi.staticWith()); MOZ_ASSERT(funEnclosingScopeIndex < i); @@ -3295,10 +3303,16 @@ js::detail::CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScri Rooted innerBlock(cx, &obj->as()); RootedObject enclosingScope(cx); - if (NestedScopeObject* enclosingBlock = innerBlock->enclosingNestedScope()) - enclosingScope = objects[FindScopeObjectIndex(src, *enclosingBlock)]; - else + if (NestedScopeObject* enclosingBlock = innerBlock->enclosingNestedScope()) { + if (IsStaticGlobalLexicalScope(enclosingBlock)) { + MOZ_ASSERT(IsStaticGlobalLexicalScope(scriptStaticScope)); + enclosingScope = scriptStaticScope; + } else { + enclosingScope = objects[FindScopeObjectIndex(src, *enclosingBlock)]; + } + } else { enclosingScope = scriptStaticScope; + } clone = CloneNestedScopeObject(cx, enclosingScope, innerBlock); } else if (obj->is()) { diff --git a/js/src/vm/Interpreter.h b/js/src/vm/Interpreter.h index dde54ca09138..f985c20a27e2 100644 --- a/js/src/vm/Interpreter.h +++ b/js/src/vm/Interpreter.h @@ -14,6 +14,8 @@ #include "jsiter.h" #include "jspubtd.h" +#include "frontend/ParseNode.h" + #include "vm/Stack.h" namespace js { diff --git a/js/src/vm/Opcodes.h b/js/src/vm/Opcodes.h index fc5d0e0a791e..22e3689a4156 100644 --- a/js/src/vm/Opcodes.h +++ b/js/src/vm/Opcodes.h @@ -214,15 +214,9 @@ * Stack: v1, v2 => v1, v2, v1, v2 */ \ macro(JSOP_DUP2, 13, "dup2", NULL, 1, 2, 4, JOF_BYTE) \ - /* - * Defines a readonly property on the frame's current variables-object (the - * scope object on the scope chain designated to receive new variables). - * Category: Variables and Scopes - * Type: Variables - * Operands: uint32_t nameIndex - * Stack: val => val - */ \ - macro(JSOP_SETCONST, 14, "setconst", NULL, 5, 1, 1, JOF_ATOM|JOF_NAME|JOF_SET) \ + \ + macro(JSOP_UNUSED14, 14, "unused14", NULL, 1, 0, 0, JOF_BYTE) \ + \ /* * Pops the top two values 'lval' and 'rval' from the stack, then pushes * the result of the operation applied to the two operands, converting @@ -1295,14 +1289,10 @@ * Stack: => */ \ macro(JSOP_DEFFUN, 127,"deffun", NULL, 5, 0, 0, JOF_OBJECT) \ - /* - * Defines the new binding on the frame's current variables-object (the - * scope object on the scope chain designated to receive new variables) with - * 'READONLY' attribute. The binding is *not* JSPROP_PERMANENT. See bug - * 1019181 for the reason. + /* Defines the new constant binding on global lexical scope. * - * This is used for global scripts and also in some cases for function - * scripts where use of dynamic scoping inhibits optimization. + * Throws if a binding with the same name already exists on the scope, or + * if a var binding with the same name exists on the global. * Category: Variables and Scopes * Type: Variables * Operands: uint32_t nameIndex @@ -1313,6 +1303,9 @@ * Defines the new binding on the frame's current variables-object (the * scope object on the scope chain designated to receive new variables). * + * Throws if the current variables-object is the global object and a + * binding with the same name exists on the global lexical scope. + * * This is used for global scripts and also in some cases for function * scripts where use of dynamic scoping inhibits optimization. * Category: Variables and Scopes @@ -1655,8 +1648,27 @@ */ \ macro(JSOP_REGEXP, 160,"regexp", NULL, 5, 0, 1, JOF_REGEXP) \ \ - macro(JSOP_UNUSED161, 161,"unused161", NULL, 1, 0, 0, JOF_BYTE) \ - macro(JSOP_UNUSED162, 162,"unused162", NULL, 1, 0, 0, JOF_BYTE) \ + /* + * Initializes an uninitialized global lexical binding with the top of + * stack value. + * Category: Variables and Scopes + * Type: Free Variables + * Operands: uint32_t nameIndex + * Stack: val => val + */ \ + macro(JSOP_INITGLEXICAL, 161,"initglexical", NULL, 5, 1, 1, JOF_ATOM|JOF_NAME|JOF_SET|JOF_GNAME) \ + \ + /* Defines the new mutable binding on global lexical scope. + * + * Throws if a binding with the same name already exists on the scope, or + * if a var binding with the same name exists on the global. + * Category: Variables and Scopes + * Type: Variables + * Operands: uint32_t nameIndex + * Stack: => + */ \ + macro(JSOP_DEFLET, 162,"deflet", NULL, 5, 0, 0, JOF_ATOM) \ + \ macro(JSOP_UNUSED163, 163,"unused163", NULL, 1, 0, 0, JOF_BYTE) \ macro(JSOP_UNUSED164, 164,"unused164", NULL, 1, 0, 0, JOF_BYTE) \ macro(JSOP_UNUSED165, 165,"unused165", NULL, 1, 0, 0, JOF_BYTE) \ diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 0a14bd78d4c6..303fbb5b9d19 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -1038,11 +1038,13 @@ js::XDRStaticBlockObject(XDRState* xdr, HandleObject enclosingScope, Rooted obj(cx); uint32_t count = 0, offset = 0; + uint8_t extensible = 0; if (mode == XDR_ENCODE) { obj = objp; count = obj->numVariables(); offset = obj->localOffset(); + extensible = obj->isExtensible() ? 1 : 0; } if (mode == XDR_DECODE) { @@ -1057,6 +1059,8 @@ js::XDRStaticBlockObject(XDRState* xdr, HandleObject enclosingScope, return false; if (!xdr->codeUint32(&offset)) return false; + if (!xdr->codeUint8(&extensible)) + return false; /* * XDR the block object's properties. We know that there are 'count' @@ -1090,6 +1094,11 @@ js::XDRStaticBlockObject(XDRState* xdr, HandleObject enclosingScope, bool aliased = !!(propFlags >> 1); obj->setAliased(i, aliased); } + + if (!extensible) { + if (!obj->makeNonExtensible(cx)) + return false; + } } else { Rooted shapes(cx, ShapeVector(cx)); if (!shapes.growBy(count)) diff --git a/js/src/vm/ScopeObject.h b/js/src/vm/ScopeObject.h index 6d38295c2177..b9df7fe09dd8 100644 --- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -661,14 +661,6 @@ class StaticBlockObject : public BlockObject */ inline StaticBlockObject* enclosingBlock() const; - StaticEvalObject* maybeEnclosingEval() const { - if (JSObject* enclosing = enclosingStaticScope()) { - if (enclosing->is()) - return &enclosing->as(); - } - return nullptr; - } - uint32_t localOffset() { return getReservedSlot(LOCAL_OFFSET_SLOT).toPrivateUint32(); } From 78aa3b827776738740e0816d25b06d210b61b3bc Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Tue, 6 Oct 2015 14:00:29 -0700 Subject: [PATCH 084/228] Bug 589199 - Support global lexicals in the interpreter. (r=efaust) --- js/src/jsapi.cpp | 2 +- js/src/jsfun.cpp | 3 +- js/src/jsscript.cpp | 12 +++-- js/src/vm/Debugger.cpp | 19 ++++---- js/src/vm/Interpreter-inl.h | 96 +++++++++++++++++++++++++++---------- js/src/vm/Interpreter.cpp | 80 +++++++++++++++++++------------ js/src/vm/Interpreter.h | 14 +++--- js/src/vm/ScopeObject.cpp | 4 ++ js/src/vm/Stack.cpp | 9 +++- js/src/vm/Xdr.cpp | 7 ++- 10 files changed, 165 insertions(+), 81 deletions(-) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index a9bfc3db8189..c341a4d97064 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -4477,7 +4477,7 @@ ExecuteScript(JSContext* cx, AutoObjectVector& scopeChain, HandleScript scriptAr return false; RootedScript script(cx, scriptArg); - if (!script->hasNonSyntacticScope() && !dynamicScope->is()) { + if (!script->hasNonSyntacticScope() && !IsGlobalLexicalScope(dynamicScope)) { script = CloneGlobalScript(cx, staticScope, script); if (!script) return false; diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index a0c3f62f2398..080f7b82e41f 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -590,9 +590,8 @@ js::XDRInterpretedFunction(XDRState* xdr, HandleObject enclosingScope, Han gc::AllocKind allocKind = gc::AllocKind::FUNCTION; if (uint16_t(flagsword) & JSFunction::EXTENDED) allocKind = gc::AllocKind::FUNCTION_EXTENDED; - RootedObject globalLexical(cx, &cx->global()->lexicalScope()); fun = NewFunctionWithProto(cx, nullptr, 0, JSFunction::INTERPRETED, - globalLexical, nullptr, proto, + /* enclosingDynamicScope = */ nullptr, nullptr, proto, allocKind, TenuredObject); if (!fun) return false; diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 426216bb7287..0b7fdec03f07 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -579,6 +579,8 @@ js::XDRScript(XDRState* xdr, HandleObject enclosingScopeArg, HandleScript { /* NB: Keep this in sync with CopyScript. */ + MOZ_ASSERT(enclosingScopeArg); + enum ScriptBits { NoScriptRval, SavedCallerFun, @@ -807,8 +809,10 @@ js::XDRScript(XDRState* xdr, HandleObject enclosingScopeArg, HandleScript // If the outermost script has a non-syntactic scope, reflect that on // the static scope chain. - if (scriptBits & (1 << HasNonSyntacticScope) && !enclosingScope) { - enclosingScope = StaticNonSyntacticScopeObjects::create(cx, nullptr); + if (scriptBits & (1 << HasNonSyntacticScope) && + IsStaticGlobalLexicalScope(enclosingScope)) + { + enclosingScope = StaticNonSyntacticScopeObjects::create(cx, enclosingScope); if (!enclosingScope) return false; } @@ -3495,7 +3499,7 @@ CreateEmptyScriptForClone(JSContext* cx, HandleObject enclosingScope, HandleScri JSScript* js::CloneGlobalScript(JSContext* cx, Handle enclosingScope, HandleScript src) { - MOZ_ASSERT(IsGlobalLexicalScope(enclosingScope) || + MOZ_ASSERT(IsStaticGlobalLexicalScope(enclosingScope) || enclosingScope->is()); RootedScript dst(cx, CreateEmptyScriptForClone(cx, enclosingScope, src)); @@ -3815,7 +3819,7 @@ JSScript::calculateLiveFixed(jsbytecode* pc) staticScope = MaybeForwarded(staticScope); } - if (staticScope) { + if (staticScope && !IsStaticGlobalLexicalScope(staticScope)) { StaticBlockObject& blockObj = staticScope->as(); nlivefixed = blockObj.localOffset() + blockObj.numVariables(); } diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index b2dee19a1624..b631e8c077b6 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -6518,18 +6518,19 @@ EvaluateInEnv(JSContext* cx, Handle env, HandleValue thisv, AbstractFrameP MOZ_ASSERT_IF(frame, pc); /* - * NB: This function breaks the assumption that the compiler can see all - * calls and properly compute a static level. In practice, any non-zero - * static level will suffice. - * * Pass in a StaticEvalObject *not* linked to env for evalStaticScope, as * ScopeIter should stop at any non-ScopeObject or non-syntactic With * boundaries, and we are putting a DebugScopeProxy or non-syntactic With on * the scope chain. */ Rooted enclosingStaticScope(cx); - if (!env->is()) + if (!IsGlobalLexicalScope(env)) { enclosingStaticScope = StaticNonSyntacticScopeObjects::create(cx, nullptr); + if (!enclosingStaticScope) + return false; + } else { + enclosingStaticScope = &cx->global()->lexicalScope().staticBlock(); + } // Do not consider executeInGlobal{WithBindings} as an eval, but instead // as executing a series of statements at the global level. This is to @@ -6582,7 +6583,7 @@ DebuggerGenericEval(JSContext* cx, const char* fullMethodName, const Value& code { /* Either we're specifying the frame, or a global. */ MOZ_ASSERT_IF(iter, !scope); - MOZ_ASSERT_IF(!iter, scope && scope->is()); + MOZ_ASSERT_IF(!iter, scope && IsGlobalLexicalScope(scope)); if (iter && iter->script()->isDerivedClassConstructor()) { MOZ_ASSERT(iter->isFunctionFrame() && iter->calleeTemplate()->isClassConstructor()); @@ -7628,9 +7629,10 @@ DebuggerObject_executeInGlobal(JSContext* cx, unsigned argc, Value* vp) if (!RequireGlobalObject(cx, args.thisv(), referent)) return false; + RootedObject globalLexical(cx, &referent->as().lexicalScope()); return DebuggerGenericEval(cx, "Debugger.Object.prototype.executeInGlobal", args[0], EvalWithDefaultBindings, JS::UndefinedHandleValue, - args.get(1), args.rval(), dbg, referent, nullptr); + args.get(1), args.rval(), dbg, globalLexical, nullptr); } static bool @@ -7643,9 +7645,10 @@ DebuggerObject_executeInGlobalWithBindings(JSContext* cx, unsigned argc, Value* if (!RequireGlobalObject(cx, args.thisv(), referent)) return false; + RootedObject globalLexical(cx, &referent->as().lexicalScope()); return DebuggerGenericEval(cx, "Debugger.Object.prototype.executeInGlobalWithBindings", args[0], EvalHasExtraBindings, args[1], args.get(2), - args.rval(), dbg, referent, nullptr); + args.rval(), dbg, globalLexical, nullptr); } static bool diff --git a/js/src/vm/Interpreter-inl.h b/js/src/vm/Interpreter-inl.h index cd64cd8cf012..b6ef9630e226 100644 --- a/js/src/vm/Interpreter-inl.h +++ b/js/src/vm/Interpreter-inl.h @@ -273,10 +273,11 @@ SetNameOperation(JSContext* cx, JSScript* script, jsbytecode* pc, HandleObject s *pc == JSOP_STRICTSETNAME || *pc == JSOP_SETGNAME || *pc == JSOP_STRICTSETGNAME); - MOZ_ASSERT_IF(*pc == JSOP_SETGNAME && !script->hasNonSyntacticScope(), - scope == cx->global()); - MOZ_ASSERT_IF(*pc == JSOP_STRICTSETGNAME && !script->hasNonSyntacticScope(), - scope == cx->global()); + MOZ_ASSERT_IF((*pc == JSOP_SETGNAME || *pc == JSOP_STRICTSETGNAME) && + !script->hasNonSyntacticScope(), + scope == cx->global() || + scope == &cx->global()->lexicalScope() || + scope->is()); bool strict = *pc == JSOP_STRICTSETNAME || *pc == JSOP_STRICTSETGNAME; RootedPropertyName name(cx, script->getName(pc)); @@ -298,6 +299,61 @@ SetNameOperation(JSContext* cx, JSScript* script, jsbytecode* pc, HandleObject s return ok && result.checkStrictErrorOrWarning(cx, scope, id, strict); } +inline bool +DefLexicalOperation(JSContext* cx, HandlePropertyName name, unsigned attrs) +{ + Rooted globalLexical(cx, &cx->global()->lexicalScope()); + + // Due to the extensibility of the global lexical scope, we must check for + // redeclaring a binding. + mozilla::Maybe redeclKind; + RootedId id(cx, NameToId(name)); + RootedShape shape(cx); + if ((shape = globalLexical->lookup(cx, name))) { + redeclKind = mozilla::Some(shape->writable() ? frontend::Definition::LET + : frontend::Definition::CONST); + } else if ((shape = cx->global()->lookup(cx, name))) { + if (!shape->configurable()) + redeclKind = mozilla::Some(frontend::Definition::VAR); + } else { + Rooted desc(cx); + if (!GetOwnPropertyDescriptor(cx, varObj, id, &desc)) + return false; + if (desc.object() && desc.hasConfigurable() && !desc.configurable()) + redeclKind = mozilla::Some(frontend::Definition::VAR); + } + if (redeclKind.isSome()) { + ReportRuntimeRedeclaration(cx, name, *redeclKind); + return false; + } + + RootedValue uninitialized(cx, MagicValue(JS_UNINITIALIZED_LEXICAL)); + return NativeDefineProperty(cx, lexicalScope, id, uninitialized, nullptr, nullptr, attrs); +} + +inline bool +DefLexicalOperation(JSContext* cx, JSScript* script, jsbytecode* pc) +{ + MOZ_ASSERT(*pc == JSOP_DEFLET || *pc == JSOP_DEFCONST); + RootedPropertyName name(cx, script->getName(pc)); + + unsigned attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT; + if (*pc == JSOP_DEFCONST) + attrs |= JSPROP_READONLY; + + return DefLexicalOperation(cx, name, attrs); +} + +inline void +InitGlobalLexicalOperation(JSContext* cx, JSScript* script, jsbytecode* pc, HandleValue value) +{ + MOZ_ASSERT(*pc == JSOP_INITGLEXICAL); + Rooted globalLexical(cx, &cx->global()->lexicalScope()); + RootedShape shape(cx, globalLexical->lookup(cx, script->getName(pc))); + MOZ_ASSERT(shape); + globalLexical->setSlot(shape->slot(), value); +} + inline bool InitPropertyOperation(JSContext* cx, JSOp op, HandleObject obj, HandleId id, HandleValue rhs) { @@ -312,10 +368,20 @@ InitPropertyOperation(JSContext* cx, JSOp op, HandleObject obj, HandleId id, Han } inline bool -DefVarOrConstOperation(JSContext* cx, HandleObject varobj, HandlePropertyName dn, unsigned attrs) +DefVarOperation(JSContext* cx, HandleObject varobj, HandlePropertyName dn, unsigned attrs) { MOZ_ASSERT(varobj->isQualifiedVarObj()); + // Due to the extensibility of the global lexical scope, we must check for + // redeclaring a lexical binding. + if (varobj == cx->global()) { + if (Shape* shape = cx->global()->lexicalScope().lookup(cx, dn)) { + ReportRuntimeRedeclaration(cx, dn, shape->writable() ? frontend::Definition::LET + : frontend::Definition::CONST); + return false; + } + } + RootedShape prop(cx); RootedObject obj2(cx); if (!LookupProperty(cx, varobj, dn, &obj2, &prop)) @@ -325,26 +391,6 @@ DefVarOrConstOperation(JSContext* cx, HandleObject varobj, HandlePropertyName dn if (!prop || (obj2 != varobj && varobj->is())) { if (!DefineProperty(cx, varobj, dn, UndefinedHandleValue, nullptr, nullptr, attrs)) return false; - } else if (attrs & JSPROP_READONLY) { - /* - * Extension: ordinarily we'd be done here -- but for |const|. If we - * see a redeclaration that's |const|, we consider it a conflict. - */ - RootedId id(cx, NameToId(dn)); - Rooted desc(cx); - if (!GetOwnPropertyDescriptor(cx, obj2, id, &desc)) - return false; - - JSAutoByteString bytes; - if (AtomToPrintableString(cx, dn, &bytes)) { - bool isConst = desc.hasWritable() && !desc.writable(); - JS_ALWAYS_FALSE(JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, - GetErrorMessage, - nullptr, JSMSG_REDECLARED_VAR, - isConst ? "const" : "var", - bytes.ptr())); - } - return false; } return true; diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 3953d368e2d8..4fd40e6fd914 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -278,14 +278,14 @@ GetNameOperation(JSContext* cx, InterpreterFrame* fp, jsbytecode* pc, MutableHan * before the global object. */ if (IsGlobalOp(JSOp(*pc)) && !fp->script()->hasNonSyntacticScope()) - obj = &obj->global(); + obj = &obj->global().lexicalScope(); Shape* shape = nullptr; JSObject* scope = nullptr; JSObject* pobj = nullptr; if (LookupNameNoGC(cx, name, obj, &scope, &pobj, &shape)) { if (FetchNameNoGC(pobj, shape, vp)) - return CheckUninitializedLexical(cx, name, vp); + return true; } RootedObject objRoot(cx, obj), scopeRoot(cx), pobjRoot(cx); @@ -2051,9 +2051,8 @@ CASE(EnableInterruptsPseudoOpcode) /* Various 1-byte no-ops. */ CASE(JSOP_NOP) CASE(JSOP_UNUSED2) +CASE(JSOP_UNUSED14) CASE(JSOP_BACKPATCH) -CASE(JSOP_UNUSED161) -CASE(JSOP_UNUSED162) CASE(JSOP_UNUSED163) CASE(JSOP_UNUSED164) CASE(JSOP_UNUSED165) @@ -2394,17 +2393,6 @@ CASE(JSOP_PICK) } END_CASE(JSOP_PICK) -CASE(JSOP_SETCONST) -{ - ReservedRooted name(&rootName0, script->getName(REGS.pc)); - ReservedRooted rval(&rootValue0, REGS.sp[-1]); - ReservedRooted obj(&rootObject0, ®S.fp()->varObj()); - - if (!SetConstOperation(cx, obj, name, rval)) - goto error; -} -END_CASE(JSOP_SETCONST) - CASE(JSOP_BINDINTRINSIC) { NativeObject* holder = GlobalObject::getIntrinsicsHolder(cx, cx->global()); @@ -2419,19 +2407,19 @@ CASE(JSOP_BINDGNAME) CASE(JSOP_BINDNAME) { JSOp op = JSOp(*REGS.pc); - if (op == JSOP_BINDNAME || script->hasNonSyntacticScope()) { - ReservedRooted scopeChain(&rootObject0, REGS.fp()->scopeChain()); - ReservedRooted name(&rootName0, script->getName(REGS.pc)); + ReservedRooted scopeChain(&rootObject0); + if (op == JSOP_BINDNAME || script->hasNonSyntacticScope()) + scopeChain.set(REGS.fp()->scopeChain()); + else + scopeChain.set(®S.fp()->global().lexicalScope()); + ReservedRooted name(&rootName0, script->getName(REGS.pc)); - /* Assigning to an undeclared name adds a property to the global object. */ - ReservedRooted scope(&rootObject1); - if (!LookupNameUnqualified(cx, name, scopeChain, &scope)) - goto error; + /* Assigning to an undeclared name adds a property to the global object. */ + ReservedRooted scope(&rootObject1); + if (!LookupNameUnqualified(cx, name, scopeChain, &scope)) + goto error; - PUSH_OBJECT(*scope); - } else { - PUSH_OBJECT(REGS.fp()->global()); - } + PUSH_OBJECT(*scope); static_assert(JSOP_BINDNAME_LENGTH == JSOP_BINDGNAME_LENGTH, "We're sharing the END_CASE so the lengths better match"); @@ -3439,6 +3427,13 @@ CASE(JSOP_INITALIASEDLEXICAL) } END_CASE(JSOP_INITALIASEDLEXICAL) +CASE(JSOP_INITGLEXICAL) +{ + HandleValue value = REGS.stackHandleAt(-1); + InitGlobalLexicalOperation(cx, script, REGS.pc, value); +} +END_CASE(JSOP_INITGLEXICAL) + CASE(JSOP_UNINITIALIZED) PUSH_UNINITIALIZED(); END_CASE(JSOP_UNINITIALIZED) @@ -3488,25 +3483,30 @@ CASE(JSOP_SETLOCAL) } END_CASE(JSOP_SETLOCAL) -CASE(JSOP_DEFCONST) CASE(JSOP_DEFVAR) { /* ES5 10.5 step 8 (with subsequent errata). */ unsigned attrs = JSPROP_ENUMERATE; - if (*REGS.pc == JSOP_DEFCONST) - attrs |= JSPROP_READONLY; - else if (!REGS.fp()->isEvalFrame()) + if (!REGS.fp()->isEvalFrame()) attrs |= JSPROP_PERMANENT; /* Step 8b. */ ReservedRooted obj(&rootObject0, ®S.fp()->varObj()); ReservedRooted name(&rootName0, script->getName(REGS.pc)); - if (!DefVarOrConstOperation(cx, obj, name, attrs)) + if (!DefVarOperation(cx, obj, name, attrs)) goto error; } END_CASE(JSOP_DEFVAR) +CASE(JSOP_DEFCONST) +CASE(JSOP_DEFLET) +{ + if (!DefLexicalOperation(cx, script, REGS.pc)) + goto error; +} +END_CASE(JSOP_DEFLET) + CASE(JSOP_DEFFUN) { /* @@ -4948,3 +4948,21 @@ js::ReportUninitializedLexical(JSContext* cx, HandleScript script, jsbytecode* p ReportUninitializedLexical(cx, name); } + +void +js::ReportRuntimeRedeclaration(JSContext* cx, HandlePropertyName name, + frontend::Definition::Kind declKind) +{ + JSAutoByteString printable; + if (AtomToPrintableString(cx, name, &printable)) { + // We cannot distinguish 'var' declarations from manually defined, + // non-configurable global properties. + const char* kindStr; + if (declKind == frontend::Definition::VAR) + kindStr = "non-configurable global property"; + else + kindStr = frontend::Definition::kindString(declKind); + JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_REDECLARED_VAR, + kindStr, printable.ptr()); + } +} diff --git a/js/src/vm/Interpreter.h b/js/src/vm/Interpreter.h index f985c20a27e2..68bc3b4745c2 100644 --- a/js/src/vm/Interpreter.h +++ b/js/src/vm/Interpreter.h @@ -473,19 +473,19 @@ NewArrayOperation(JSContext* cx, HandleScript script, jsbytecode* pc, uint32_t l JSObject* NewArrayOperationWithTemplate(JSContext* cx, HandleObject templateObject); -inline bool -SetConstOperation(JSContext* cx, HandleObject varobj, HandlePropertyName name, HandleValue rval) -{ - return DefineProperty(cx, varobj, name, rval, nullptr, nullptr, - JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY); -} - void ReportUninitializedLexical(JSContext* cx, HandlePropertyName name); void ReportUninitializedLexical(JSContext* cx, HandleScript script, jsbytecode* pc); +// The parser only reports redeclarations that occurs within a single +// script. Due to the extensibility of the global lexical scope, we also check +// for redeclarations during runtime in JSOP_DEF{VAR,LET,CONST}. +void +ReportRuntimeRedeclaration(JSContext* cx, HandlePropertyName name, + frontend::Definition::Kind declKind); + } /* namespace js */ #endif /* vm_Interpreter_h */ diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 303fbb5b9d19..26ad1c22a423 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -1666,6 +1666,10 @@ class DebugScopeProxy : public BaseProxyHandler if (!shape) return true; + // Currently consider all global lexical bindings to be aliased. + if (IsGlobalLexicalScope(block)) + return true; + unsigned i = block->staticBlock().shapeToIndex(*shape); if (block->staticBlock().isAliased(i)) return true; diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 94879d6e9cec..64d4b506b483 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -179,7 +179,14 @@ AssertDynamicScopeMatchesStaticScope(JSContext* cx, JSScript* script, JSObject* } } - MOZ_ASSERT(scope->is() || scope->is()); + // In the case of a non-syntactic scope chain, the immediate parent of the + // outermost non-syntactic scope may be the global lexical scope, or, if + // called from Debugger, a DebugScopeObject. + // + // In the case of a syntactic scope chain, the outermost scope is always a + // GlobalObject. + MOZ_ASSERT(scope->is() || IsGlobalLexicalScope(scope) || + scope->is()); #endif } diff --git a/js/src/vm/Xdr.cpp b/js/src/vm/Xdr.cpp index ce0eb8125d69..f648c4318d50 100644 --- a/js/src/vm/Xdr.cpp +++ b/js/src/vm/Xdr.cpp @@ -12,6 +12,7 @@ #include "jsscript.h" #include "vm/Debugger.h" +#include "vm/ScopeObject.h" using namespace js; @@ -117,7 +118,8 @@ XDRState::codeFunction(MutableHandleFunction objp) if (!VersionCheck(this)) return false; - return XDRInterpretedFunction(this, nullptr, nullptr, objp); + RootedObject staticLexical(cx(), &cx()->global()->lexicalScope().staticBlock()); + return XDRInterpretedFunction(this, staticLexical, nullptr, objp); } template @@ -130,7 +132,8 @@ XDRState::codeScript(MutableHandleScript scriptp) if (!VersionCheck(this)) return false; - if (!XDRScript(this, nullptr, nullptr, nullptr, scriptp)) + RootedObject staticLexical(cx(), &cx()->global()->lexicalScope().staticBlock()); + if (!XDRScript(this, staticLexical, nullptr, nullptr, scriptp)) return false; return true; From 934bb0bb1327a71a0a837a7579daf40e22aa3e6d Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Tue, 6 Oct 2015 14:00:29 -0700 Subject: [PATCH 085/228] Bug 589199 - Support global lexicals in Baseline. (r=jandem) --- js/src/jit/BaselineCompiler.cpp | 67 ++++++--- js/src/jit/BaselineCompiler.h | 3 +- js/src/jit/BaselineDebugModeOSR.cpp | 4 +- js/src/jit/BaselineFrameInfo.cpp | 7 +- js/src/jit/BaselineIC.cpp | 217 +++++++++++++++++++++------- js/src/jit/BaselineIC.h | 182 +++++++++++++++-------- js/src/jit/BaselineICList.h | 2 + js/src/jit/JitFrames.cpp | 2 +- js/src/jit/SharedIC.cpp | 14 +- js/src/jit/SharedIC.h | 2 + js/src/jit/VMFunctions.cpp | 15 +- js/src/jit/VMFunctions.h | 3 +- 12 files changed, 363 insertions(+), 155 deletions(-) diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index 8bd153bf2b17..c4daec484a12 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -2115,6 +2115,7 @@ BaselineCompiler::emit_JSOP_GETGNAME() RootedPropertyName name(cx, script->getName(pc)); + // These names are non-configurable on the global and cannot be shadowed. if (name == cx->names().undefined) { frame.push(UndefinedValue()); return true; @@ -2130,7 +2131,7 @@ BaselineCompiler::emit_JSOP_GETGNAME() frame.syncStack(0); - masm.movePtr(ImmGCPtr(&script->global()), R0.scratchReg()); + masm.movePtr(ImmGCPtr(&script->global().lexicalScope()), R0.scratchReg()); // Call IC. ICGetName_Fallback::Compiler stubCompiler(cx); @@ -2146,8 +2147,27 @@ bool BaselineCompiler::emit_JSOP_BINDGNAME() { if (!script->hasNonSyntacticScope()) { - frame.push(ObjectValue(script->global())); - return true; + // We can bind name to the global lexical scope if the binding already + // exists and is initialized at compile time. + RootedPropertyName name(cx, script->getName(pc)); + Rooted globalLexical(cx, &script->global().lexicalScope()); + if (Shape* shape = globalLexical->lookup(cx, name)) { + if (!globalLexical->getSlot(shape->slot()).isMagic(JS_UNINITIALIZED_LEXICAL)) { + frame.push(ObjectValue(*globalLexical)); + return true; + } + } + + // We can bind name to the global object if the property exists on the + // global and is non-configurable, as then it cannot be shadowed. + if (Shape* shape = script->global().lookup(cx, name)) { + if (!shape->configurable()) { + frame.push(ObjectValue(script->global())); + return true; + } + } + + // Otherwise we have to use the dynamic scope chain. } return emit_JSOP_BINDNAME(); @@ -2437,8 +2457,8 @@ BaselineCompiler::emit_JSOP_GETINTRINSIC() return true; } -typedef bool (*DefVarOrConstFn)(JSContext*, HandlePropertyName, unsigned, HandleObject); -static const VMFunction DefVarOrConstInfo = FunctionInfo(DefVarOrConst); +typedef bool (*DefVarFn)(JSContext*, HandlePropertyName, unsigned, HandleObject); +static const VMFunction DefVarInfo = FunctionInfo(DefVar); bool BaselineCompiler::emit_JSOP_DEFVAR() @@ -2446,9 +2466,7 @@ BaselineCompiler::emit_JSOP_DEFVAR() frame.syncStack(0); unsigned attrs = JSPROP_ENUMERATE; - if (JSOp(*pc) == JSOP_DEFCONST) - attrs |= JSPROP_READONLY; - else if (!script->isForEval()) + if (!script->isForEval()) attrs |= JSPROP_PERMANENT; MOZ_ASSERT(attrs <= UINT32_MAX); @@ -2460,34 +2478,34 @@ BaselineCompiler::emit_JSOP_DEFVAR() pushArg(Imm32(attrs)); pushArg(ImmGCPtr(script->getName(pc))); - return callVM(DefVarOrConstInfo); + return callVM(DefVarInfo); } +typedef bool (*DefLexicalFn)(JSContext*, HandlePropertyName, unsigned); +static const VMFunction DefLexicalInfo = FunctionInfo(DefLexicalOperation); + bool BaselineCompiler::emit_JSOP_DEFCONST() { - return emit_JSOP_DEFVAR(); + return emit_JSOP_DEFLET(); } -typedef bool (*SetConstFn)(JSContext*, HandlePropertyName, HandleObject, HandleValue); -static const VMFunction SetConstInfo = FunctionInfo(SetConst); - bool -BaselineCompiler::emit_JSOP_SETCONST() +BaselineCompiler::emit_JSOP_DEFLET() { - frame.popRegsAndSync(1); - frame.push(R0); frame.syncStack(0); - masm.loadPtr(frame.addressOfScopeChain(), R1.scratchReg()); + unsigned attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT; + if (*pc == JSOP_DEFCONST) + attrs |= JSPROP_READONLY; + MOZ_ASSERT(attrs <= UINT32_MAX); prepareVMCall(); - pushArg(R0); - pushArg(R1.scratchReg()); + pushArg(Imm32(attrs)); pushArg(ImmGCPtr(script->getName(pc))); - return callVM(SetConstInfo); + return callVM(DefLexicalInfo); } typedef bool (*DefFunOperationFn)(JSContext*, HandleScript, HandleObject, HandleFunction); @@ -2818,6 +2836,15 @@ BaselineCompiler::emit_JSOP_INITLEXICAL() return emit_JSOP_SETLOCAL(); } +bool +BaselineCompiler::emit_JSOP_INITGLEXICAL() +{ + frame.popRegsAndSync(1); + frame.push(ObjectValue(script->global().lexicalScope())); + frame.push(R0); + return emit_JSOP_SETPROP(); +} + bool BaselineCompiler::emit_JSOP_CHECKALIASEDLEXICAL() { diff --git a/js/src/jit/BaselineCompiler.h b/js/src/jit/BaselineCompiler.h index f082ee9e81c1..6a4eb2c430a0 100644 --- a/js/src/jit/BaselineCompiler.h +++ b/js/src/jit/BaselineCompiler.h @@ -141,7 +141,7 @@ namespace jit { _(JSOP_GETINTRINSIC) \ _(JSOP_DEFVAR) \ _(JSOP_DEFCONST) \ - _(JSOP_SETCONST) \ + _(JSOP_DEFLET) \ _(JSOP_DEFFUN) \ _(JSOP_GETLOCAL) \ _(JSOP_SETLOCAL) \ @@ -149,6 +149,7 @@ namespace jit { _(JSOP_SETARG) \ _(JSOP_CHECKLEXICAL) \ _(JSOP_INITLEXICAL) \ + _(JSOP_INITGLEXICAL) \ _(JSOP_CHECKALIASEDLEXICAL) \ _(JSOP_INITALIASEDLEXICAL) \ _(JSOP_UNINITIALIZED) \ diff --git a/js/src/jit/BaselineDebugModeOSR.cpp b/js/src/jit/BaselineDebugModeOSR.cpp index 4ad1a8960d2d..2884c81cd43c 100644 --- a/js/src/jit/BaselineDebugModeOSR.cpp +++ b/js/src/jit/BaselineDebugModeOSR.cpp @@ -696,6 +696,7 @@ RecompileBaselineScriptForDebugMode(JSContext* cx, JSScript* script, _(GetElem_NativePrototypeCallScriptedSymbol) \ _(GetProp_CallScripted) \ _(GetProp_CallNative) \ + _(GetProp_CallNativeGlobal) \ _(GetProp_CallDOMProxyNative) \ _(GetProp_CallDOMProxyWithGenerationNative) \ _(GetProp_DOMProxyShadowed) \ @@ -708,7 +709,8 @@ RecompileBaselineScriptForDebugMode(JSContext* cx, JSScript* script, _(GetElem_Dense) \ _(GetElem_Arguments) \ _(GetProp_NativePrototype) \ - _(GetProp_Native) + _(GetProp_Native) \ + _(GetName_Global) #endif static bool diff --git a/js/src/jit/BaselineFrameInfo.cpp b/js/src/jit/BaselineFrameInfo.cpp index be3f80704b60..535e0d33d947 100644 --- a/js/src/jit/BaselineFrameInfo.cpp +++ b/js/src/jit/BaselineFrameInfo.cpp @@ -16,8 +16,11 @@ using namespace js::jit; bool FrameInfo::init(TempAllocator& alloc) { - // One slot is always needed for this/arguments type checks. - size_t nstack = Max(script->nslots() - script->nfixed(), size_t(1)); + // The minimum stack size is two. One slot is always needed for + // this/arguments type checks. Two slots are needed because INITGLEXICAL + // (stack depth 1) is compiled as a SETPROP (stack depth 2) on the global + // lexical scope. + size_t nstack = Max(script->nslots() - script->nfixed(), size_t(2)); if (!stack.init(alloc, nstack)) return false; diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index fd82702c09f9..fa20f1f7b5e7 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -4893,25 +4893,29 @@ UpdateExistingSetPropCallStubs(ICSetProp_Fallback* fallbackStub, // Attach an optimized stub for a GETGNAME/CALLGNAME slot-read op. static bool TryAttachGlobalNameValueStub(JSContext* cx, HandleScript script, jsbytecode* pc, - ICGetName_Fallback* stub, Handle global, + ICGetName_Fallback* stub, Handle globalLexical, HandlePropertyName name, bool* attached) { - MOZ_ASSERT(global->is()); + MOZ_ASSERT(globalLexical->isGlobal()); MOZ_ASSERT(!*attached); RootedId id(cx, NameToId(name)); // The property must be found, and it must be found as a normal data property. - RootedShape shape(cx); - RootedNativeObject current(cx, global); + RootedShape shape(cx, globalLexical->lookup(cx, id)); + RootedNativeObject current(cx, globalLexical); while (true) { shape = current->lookup(cx, id); if (shape) break; - JSObject* proto = current->getProto(); - if (!proto || !proto->is()) - return true; - current = &proto->as(); + if (current == globalLexical) { + current = &globalLexical->global(); + } else { + JSObject* proto = current->getProto(); + if (!proto || !proto->is()) + return true; + current = &proto->as(); + } } // Instantiate this global property, for use during Ion compilation. @@ -4924,23 +4928,28 @@ TryAttachGlobalNameValueStub(JSContext* cx, HandleScript script, jsbytecode* pc, ICStub* monitorStub = stub->fallbackMonitorStub()->firstMonitorStub(); ICStub* newStub; - if (current == global) { + if (current == globalLexical) { MOZ_ASSERT(shape->slot() >= current->numFixedSlots()); uint32_t slot = shape->slot() - current->numFixedSlots(); - JitSpew(JitSpew_BaselineIC, " Generating GetName(GlobalName) stub"); - ICGetName_Global::Compiler compiler(cx, monitorStub, current->lastProperty(), slot); + JitSpew(JitSpew_BaselineIC, " Generating GetName(GlobalName lexical) stub"); + ICGetName_GlobalLexical::Compiler compiler(cx, monitorStub, slot); newStub = compiler.getStub(compiler.getStubSpace(script)); } else { bool isFixedSlot; uint32_t offset; GetFixedOrDynamicSlotOffset(shape, &isFixedSlot, &offset); - if (!IsCacheableGetPropReadSlot(global, current, shape)) + + // Check the prototype chain from the global to the current + // prototype. Ignore the global lexical scope as it doesn' figure + // into the prototype chain. We guard on the global lexical + // scope's shape independently. + if (!IsCacheableGetPropReadSlot(&globalLexical->global(), current, shape)) return true; - JitSpew(JitSpew_BaselineIC, " Generating GetName(GlobalName prototype) stub"); - ICGetPropNativeCompiler compiler(cx, ICStub::GetProp_NativePrototype, false, monitorStub, - global, current, name, isFixedSlot, offset, + JitSpew(JitSpew_BaselineIC, " Generating GetName(GlobalName non-lexical) stub"); + ICGetPropNativeCompiler compiler(cx, ICStub::GetName_Global, false, monitorStub, + globalLexical, current, name, isFixedSlot, offset, /* inputDefinitelyObject = */ true); newStub = compiler.getStub(compiler.getStubSpace(script)); } @@ -4956,14 +4965,19 @@ TryAttachGlobalNameValueStub(JSContext* cx, HandleScript script, jsbytecode* pc, // Attach an optimized stub for a GETGNAME/CALLGNAME getter op. static bool TryAttachGlobalNameAccessorStub(JSContext* cx, HandleScript script, jsbytecode* pc, - ICGetName_Fallback* stub, Handle global, + ICGetName_Fallback* stub, Handle globalLexical, HandlePropertyName name, bool* attached, bool* isTemporarilyUnoptimizable) { - MOZ_ASSERT(global->is()); - + MOZ_ASSERT(globalLexical->isGlobal()); RootedId id(cx, NameToId(name)); + // There must not be a shadowing binding on the global lexical scope. + if (globalLexical->lookup(cx, id)) + return true; + + RootedGlobalObject global(cx, &globalLexical->global()); + // The property must be found, and it must be found as a normal data property. RootedShape shape(cx); RootedNativeObject current(cx, global); @@ -4998,10 +5012,11 @@ TryAttachGlobalNameAccessorStub(JSContext* cx, HandleScript script, jsbytecode* *attached = true; return true; } - ICGetProp_CallNative::Compiler compiler(cx, monitorStub, global, current, - getter, script->pcToOffset(pc), - /* outerClass = */ nullptr, - /* inputDefinitelyObject = */ true); + ICGetPropCallNativeCompiler compiler(cx, ICStub::GetProp_CallNativeGlobal, + monitorStub, globalLexical, current, + getter, script->pcToOffset(pc), + /* outerClass = */ nullptr, + /* inputDefinitelyObject = */ true); ICStub* newStub = compiler.getStub(compiler.getStubSpace(script)); if (!newStub) @@ -5142,8 +5157,9 @@ DoGetNameFallback(JSContext* cx, BaselineFrame* frame, ICGetName_Fallback* stub_ } if (!attached && IsGlobalOp(JSOp(*pc)) && !script->hasNonSyntacticScope()) { - if (!TryAttachGlobalNameAccessorStub(cx, script, pc, stub, scopeChain.as(), - name, &attached, &isTemporarilyUnoptimizable)) + if (!TryAttachGlobalNameAccessorStub(cx, script, pc, stub, + scopeChain.as(), + name, &attached, &isTemporarilyUnoptimizable)) { return false; } @@ -5172,8 +5188,8 @@ DoGetNameFallback(JSContext* cx, BaselineFrame* frame, ICGetName_Fallback* stub_ return true; if (IsGlobalOp(JSOp(*pc)) && !script->hasNonSyntacticScope()) { - Handle global = scopeChain.as(); - if (!TryAttachGlobalNameValueStub(cx, script, pc, stub, global, name, &attached)) + Handle globalLexical = scopeChain.as(); + if (!TryAttachGlobalNameValueStub(cx, script, pc, stub, globalLexical, name, &attached)) return false; } else { if (!TryAttachScopeNameStub(cx, script, stub, scopeChain, name, &attached)) @@ -5205,7 +5221,7 @@ ICGetName_Fallback::Compiler::generateStubCode(MacroAssembler& masm) } bool -ICGetName_Global::Compiler::generateStubCode(MacroAssembler& masm) +ICGetName_GlobalLexical::Compiler::generateStubCode(MacroAssembler& masm) { MOZ_ASSERT(engine_ == Engine::Baseline); @@ -5213,13 +5229,12 @@ ICGetName_Global::Compiler::generateStubCode(MacroAssembler& masm) Register obj = R0.scratchReg(); Register scratch = R1.scratchReg(); - // Shape guard. - masm.loadPtr(Address(ICStubReg, ICGetName_Global::offsetOfShape()), scratch); - masm.branchTestObjShape(Assembler::NotEqual, obj, scratch, &failure); + // There's no need to guard on the shape. Lexical bindings are + // non-configurable, and this stub cannot be shared across globals. // Load dynamic slot. masm.loadPtr(Address(obj, NativeObject::offsetOfSlots()), obj); - masm.load32(Address(ICStubReg, ICGetName_Global::offsetOfSlot()), scratch); + masm.load32(Address(ICStubReg, ICGetName_GlobalLexical::offsetOfSlot()), scratch); masm.loadValue(BaseIndex(obj, scratch, TimesEight), R0); // Enter type monitor IC to type-check result. @@ -5789,8 +5804,9 @@ TryAttachNativeGetAccessorPropStub(JSContext* cx, HandleScript script, jsbytecod return true; } - ICGetProp_CallNative::Compiler compiler(cx, monitorStub, obj, holder, callee, - script->pcToOffset(pc), outerClass); + ICGetPropCallNativeCompiler compiler(cx, ICStub::GetProp_CallNative, + monitorStub, obj, holder, callee, + script->pcToOffset(pc), outerClass); newStub = compiler.getStub(compiler.getStubSpace(script)); } if (!newStub) @@ -6361,11 +6377,31 @@ ICGetPropNativeCompiler::getStub(ICStubSpace* space) offset_, holder_, holderShape); } + case ICStub::GetName_Global: { + MOZ_ASSERT(obj_ != holder_); + Shape* holderShape = holder_->as().lastProperty(); + Shape* globalShape = obj_->as().global().lastProperty(); + return newStub(space, getStubCode(), firstMonitorStub_, guard, + offset_, holder_, holderShape, globalShape); + } + default: MOZ_CRASH("Bad stub kind"); } } +static void +GuardGlobalObject(MacroAssembler& masm, HandleObject holder, Register globalLexicalReg, + Register holderReg, Register scratch, size_t globalShapeOffset, Label* failure) +{ + if (holder->is()) + return; + masm.extractObject(Address(globalLexicalReg, ScopeObject::offsetOfEnclosingScope()), + holderReg); + masm.loadPtr(Address(ICStubReg, globalShapeOffset), scratch); + masm.branchTestObjShape(Assembler::NotEqual, holderReg, scratch, failure); +} + bool ICGetPropNativeCompiler::generateStubCode(MacroAssembler& masm) { @@ -6393,6 +6429,7 @@ ICGetPropNativeCompiler::generateStubCode(MacroAssembler& masm) Register holderReg; if (obj_ == holder_) { + MOZ_ASSERT(kind != ICStub::GetName_Global); if (obj_->is()) { // We are loading off the expando object, so use that for the holder. holderReg = regs.takeAny(); @@ -6401,8 +6438,17 @@ ICGetPropNativeCompiler::generateStubCode(MacroAssembler& masm) holderReg = objReg; } } else { - // Shape guard holder. holderReg = regs.takeAny(); + + // If we are generating a non-lexical GETGNAME stub, we must also + // guard on the shape of the GlobalObject. + if (kind == ICStub::GetName_Global) { + MOZ_ASSERT(obj_->is() && obj_->as().isGlobal()); + GuardGlobalObject(masm, holder_, objReg, holderReg, scratch, + ICGetName_Global::offsetOfGlobalShape(), &failure); + } + + // Shape guard holder. masm.loadPtr(Address(ICStubReg, ICGetProp_NativePrototype::offsetOfHolder()), holderReg); masm.loadPtr(Address(ICStubReg, ICGetProp_NativePrototype::offsetOfHolderShape()), @@ -6657,7 +6703,7 @@ ICGetProp_CallScripted::Compiler::generateStubCode(MacroAssembler& masm) } bool -ICGetProp_CallNative::Compiler::generateStubCode(MacroAssembler& masm) +ICGetPropCallNativeCompiler::generateStubCode(MacroAssembler& masm) { MOZ_ASSERT(engine_ == Engine::Baseline); @@ -6689,12 +6735,22 @@ ICGetProp_CallNative::Compiler::generateStubCode(MacroAssembler& masm) // Shape guard. GuardReceiverObject(masm, ReceiverGuard(receiver_), objReg, scratch, - ICGetProp_CallNative::offsetOfReceiverGuard(), &failure); + ICGetPropCallGetter::offsetOfReceiverGuard(), &failure); - if (receiver_ != holder_ ) { + if (receiver_ != holder_) { Register holderReg = regs.takeAny(); - masm.loadPtr(Address(ICStubReg, ICGetProp_CallNative::offsetOfHolder()), holderReg); - masm.loadPtr(Address(ICStubReg, ICGetProp_CallNative::offsetOfHolderShape()), scratch); + + // If we are generating a non-lexical GETGNAME stub, we must also + // guard on the shape of the GlobalObject. + if (kind == ICStub::GetProp_CallNativeGlobal) { + MOZ_ASSERT(receiver_->is() && + receiver_->as().isGlobal()); + GuardGlobalObject(masm, holder_, objReg, holderReg, scratch, + ICGetProp_CallNativeGlobal::offsetOfGlobalShape(), &failure); + } + + masm.loadPtr(Address(ICStubReg, ICGetPropCallGetter::offsetOfHolder()), holderReg); + masm.loadPtr(Address(ICStubReg, ICGetPropCallGetter::offsetOfHolderShape()), scratch); masm.branchTestObjShape(Assembler::NotEqual, holderReg, scratch, &failure); regs.add(holderReg); } @@ -6711,7 +6767,12 @@ ICGetProp_CallNative::Compiler::generateStubCode(MacroAssembler& masm) // Load callee function. Register callee = regs.takeAny(); - masm.loadPtr(Address(ICStubReg, ICGetProp_CallNative::offsetOfGetter()), callee); + masm.loadPtr(Address(ICStubReg, ICGetPropCallGetter::offsetOfGetter()), callee); + + // If we're calling a getter on the global, inline the logic for the + // 'this' hook on the global lexical scope and manually push the global. + if (kind == ICStub::GetProp_CallNativeGlobal) + masm.extractObject(Address(objReg, ScopeObject::offsetOfEnclosingScope()), objReg); // Push args for vm call. masm.push(objReg); @@ -6734,6 +6795,30 @@ ICGetProp_CallNative::Compiler::generateStubCode(MacroAssembler& masm) return true; } +ICStub* +ICGetPropCallNativeCompiler::getStub(ICStubSpace* space) +{ + ReceiverGuard guard(receiver_); + Shape* holderShape = holder_->as().lastProperty(); + + switch (kind) { + case ICStub::GetProp_CallNative: + return newStub(space, getStubCode(), firstMonitorStub_, + guard, holder_, holderShape, + getter_, pcOffset_); + + case ICStub::GetProp_CallNativeGlobal: { + Shape* globalShape = receiver_->as().global().lastProperty(); + return newStub(space, getStubCode(), firstMonitorStub_, + guard, holder_, holderShape, globalShape, + getter_, pcOffset_); + } + + default: + MOZ_CRASH("Bad stub kind"); + } +} + bool ICGetPropCallDOMProxyNativeCompiler::generateStubCode(MacroAssembler& masm, Address* expandoAndGenerationAddr, @@ -7476,7 +7561,8 @@ DoSetPropFallback(JSContext* cx, BaselineFrame* frame, ICSetProp_Fallback* stub_ op == JSOP_INITLOCKEDPROP || op == JSOP_INITHIDDENPROP || op == JSOP_SETALIASEDVAR || - op == JSOP_INITALIASEDLEXICAL); + op == JSOP_INITALIASEDLEXICAL || + op == JSOP_INITGLEXICAL); RootedPropertyName name(cx); if (op == JSOP_SETALIASEDVAR || op == JSOP_INITALIASEDLEXICAL) @@ -7529,6 +7615,9 @@ DoSetPropFallback(JSContext* cx, BaselineFrame* frame, ICSetProp_Fallback* stub_ return false; } else if (op == JSOP_SETALIASEDVAR || op == JSOP_INITALIASEDLEXICAL) { obj->as().setAliasedVar(cx, ScopeCoordinate(pc), name, rhs); + } else if (op == JSOP_INITGLEXICAL) { + RootedValue v(cx, rhs); + InitGlobalLexicalOperation(cx, script, pc, v); } else { MOZ_ASSERT(op == JSOP_SETPROP || op == JSOP_STRICTSETPROP); @@ -11268,10 +11357,9 @@ ICIn_Dense::ICIn_Dense(JitCode* stubCode, HandleShape shape) shape_(shape) { } -ICGetName_Global::ICGetName_Global(JitCode* stubCode, ICStub* firstMonitorStub, Shape* shape, - uint32_t slot) - : ICMonitoredStub(GetName_Global, stubCode, firstMonitorStub), - shape_(shape), +ICGetName_GlobalLexical::ICGetName_GlobalLexical(JitCode* stubCode, ICStub* firstMonitorStub, + uint32_t slot) + : ICMonitoredStub(GetName_GlobalLexical, stubCode, firstMonitorStub), slot_(slot) { } @@ -11322,10 +11410,11 @@ ICGetProp_Native::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorS other.receiverGuard(), other.offset()); } -ICGetProp_NativePrototype::ICGetProp_NativePrototype(JitCode* stubCode, ICStub* firstMonitorStub, - ReceiverGuard guard, uint32_t offset, - JSObject* holder, Shape* holderShape) - : ICGetPropNativeStub(GetProp_NativePrototype, stubCode, firstMonitorStub, guard, offset), +ICGetPropNativePrototypeStub::ICGetPropNativePrototypeStub(ICStub::Kind kind, JitCode* stubCode, + ICStub* firstMonitorStub, + ReceiverGuard guard, uint32_t offset, + JSObject* holder, Shape* holderShape) + : ICGetPropNativeStub(kind, stubCode, firstMonitorStub, guard, offset), holder_(holder), holderShape_(holderShape) { } @@ -11336,7 +11425,24 @@ ICGetProp_NativePrototype::Clone(JSContext* cx, ICStubSpace* space, ICStub* firs { return New(cx, space, other.jitCode(), firstMonitorStub, other.receiverGuard(), other.offset(), - other.holder_, other.holderShape_); + other.holder(), other.holderShape()); +} + +ICGetName_Global::ICGetName_Global(JitCode* stubCode, ICStub* firstMonitorStub, + ReceiverGuard guard, uint32_t offset, + JSObject* holder, Shape* holderShape, Shape* globalShape) + : ICGetPropNativePrototypeStub(GetName_Global, stubCode, firstMonitorStub, guard, offset, + holder, holderShape), + globalShape_(globalShape) +{ } + +/* static */ ICGetName_Global* +ICGetName_Global::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub, + ICGetName_Global& other) +{ + return New(cx, space, other.jitCode(), firstMonitorStub, + other.receiverGuard(), other.offset(), + other.holder(), other.holderShape(), other.globalShape()); } ICGetProp_NativeDoesNotExist::ICGetProp_NativeDoesNotExist( @@ -11394,6 +11500,7 @@ ICGetPropCallGetter::ICGetPropCallGetter(Kind kind, JitCode* stubCode, ICStub* f { MOZ_ASSERT(kind == ICStub::GetProp_CallScripted || kind == ICStub::GetProp_CallNative || + kind == ICStub::GetProp_CallNativeGlobal || kind == ICStub::GetProp_CallDOMProxyNative || kind == ICStub::GetProp_CallDOMProxyWithGenerationNative); } @@ -11425,6 +11532,16 @@ ICGetProp_CallNative::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMoni other.holderShape_, other.getter_, other.pcOffset_); } +/* static */ ICGetProp_CallNativeGlobal* +ICGetProp_CallNativeGlobal::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub, + ICGetProp_CallNativeGlobal& other) +{ + return New(cx, space, other.jitCode(), firstMonitorStub, + other.receiverGuard(), other.holder_, + other.holderShape_, other.globalShape_, + other.getter_, other.pcOffset_); +} + ICSetProp_Native::ICSetProp_Native(JitCode* stubCode, ObjectGroup* group, Shape* shape, uint32_t offset) : ICUpdatedStub(SetProp_Native, stubCode), diff --git a/js/src/jit/BaselineIC.h b/js/src/jit/BaselineIC.h index 0b1daffd56bd..b36098eede0a 100644 --- a/js/src/jit/BaselineIC.h +++ b/js/src/jit/BaselineIC.h @@ -2100,47 +2100,37 @@ class ICGetName_Fallback : public ICMonitoredFallbackStub }; }; -// Optimized GETGNAME/CALLGNAME stub. -class ICGetName_Global : public ICMonitoredStub +// Optimized lexical GETGNAME stub. +class ICGetName_GlobalLexical : public ICMonitoredStub { friend class ICStubSpace; protected: // Protected to silence Clang warning. - HeapPtrShape shape_; uint32_t slot_; - ICGetName_Global(JitCode* stubCode, ICStub* firstMonitorStub, Shape* shape, uint32_t slot); + ICGetName_GlobalLexical(JitCode* stubCode, ICStub* firstMonitorStub, uint32_t slot); public: - HeapPtrShape& shape() { - return shape_; - } - static size_t offsetOfShape() { - return offsetof(ICGetName_Global, shape_); - } static size_t offsetOfSlot() { - return offsetof(ICGetName_Global, slot_); + return offsetof(ICGetName_GlobalLexical, slot_); } class Compiler : public ICStubCompiler { ICStub* firstMonitorStub_; - RootedShape shape_; uint32_t slot_; protected: bool generateStubCode(MacroAssembler& masm); public: - Compiler(JSContext* cx, ICStub* firstMonitorStub, Shape* shape, uint32_t slot) - : ICStubCompiler(cx, ICStub::GetName_Global, Engine::Baseline), + Compiler(JSContext* cx, ICStub* firstMonitorStub, uint32_t slot) + : ICStubCompiler(cx, ICStub::GetName_GlobalLexical, Engine::Baseline), firstMonitorStub_(firstMonitorStub), - shape_(cx, shape), slot_(slot) {} ICStub* getStub(ICStubSpace* space) { - return newStub(space, getStubCode(), firstMonitorStub_, shape_, - slot_); + return newStub(space, getStubCode(), firstMonitorStub_, slot_); } }; }; @@ -2577,27 +2567,16 @@ class ICGetProp_Native : public ICGetPropNativeStub ICGetProp_Native& other); }; -// Stub for accessing a property on the native prototype of a native or unboxed -// object. Note that due to the shape teleporting optimization, we only have to -// guard on the object's shape/group and the holder's shape. -class ICGetProp_NativePrototype : public ICGetPropNativeStub +class ICGetPropNativePrototypeStub : public ICGetPropNativeStub { - friend class ICStubSpace; - - protected: // Holder and its shape. HeapPtrObject holder_; HeapPtrShape holderShape_; - ICGetProp_NativePrototype(JitCode* stubCode, ICStub* firstMonitorStub, - ReceiverGuard guard, - uint32_t offset, JSObject* holder, Shape* holderShape); - - public: - static ICGetProp_NativePrototype* Clone(JSContext* cx, - ICStubSpace* space, - ICStub* firstMonitorStub, - ICGetProp_NativePrototype& other); + protected: + ICGetPropNativePrototypeStub(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub, + ReceiverGuard guard, uint32_t offset, JSObject* holder, + Shape* holderShape); public: HeapPtrObject& holder() { @@ -2607,10 +2586,59 @@ class ICGetProp_NativePrototype : public ICGetPropNativeStub return holderShape_; } static size_t offsetOfHolder() { - return offsetof(ICGetProp_NativePrototype, holder_); + return offsetof(ICGetPropNativePrototypeStub, holder_); } static size_t offsetOfHolderShape() { - return offsetof(ICGetProp_NativePrototype, holderShape_); + return offsetof(ICGetPropNativePrototypeStub, holderShape_); + } +}; + +// Stub for accessing a property on the native prototype of a native or unboxed +// object. Note that due to the shape teleporting optimization, we only have to +// guard on the object's shape/group and the holder's shape. +class ICGetProp_NativePrototype : public ICGetPropNativePrototypeStub +{ + friend class ICStubSpace; + + protected: + ICGetProp_NativePrototype(JitCode* stubCode, ICStub* firstMonitorStub, ReceiverGuard guard, + uint32_t offset, JSObject* holder, Shape* holderShape) + : ICGetPropNativePrototypeStub(GetProp_NativePrototype, stubCode, firstMonitorStub, guard, + offset, holder, holderShape) + { } + + public: + static ICGetProp_NativePrototype* Clone(JSContext* cx, + ICStubSpace* space, + ICStub* firstMonitorStub, + ICGetProp_NativePrototype& other); +}; + +// Stub for accessing a non-lexical global name. Semantically, it is really a +// getprop: the name is either on the GlobalObject or its prototype chain. We +// teleport to the object that has the name, but we also need to guard on the +// shape of the global object. +// +// The receiver object is the global lexical scope. +class ICGetName_Global : public ICGetPropNativePrototypeStub +{ + friend class ICStubSpace; + + protected: + HeapPtrShape globalShape_; + + ICGetName_Global(JitCode* stubCode, ICStub* firstMonitorStub, ReceiverGuard guard, + uint32_t slot, JSObject* holder, Shape* holderShape, Shape* globalShape); + + public: + static ICGetName_Global* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub, + ICGetName_Global& other); + + HeapPtrShape& globalShape() { + return globalShape_; + } + static size_t offsetOfGlobalShape() { + return offsetof(ICGetName_Global, globalShape_); } }; @@ -2955,7 +2983,7 @@ class ICGetPropCallGetter : public ICMonitoredStub const Class* outerClass_; virtual int32_t getKey() const { - // ICGetProp_CallNative::Compiler::getKey adds more bits to our + // ICGetPropCallNativeCompiler::getKey adds more bits to our // return value, so be careful when making changes here. return static_cast(engine_) | (static_cast(kind) << 1) | @@ -2977,7 +3005,8 @@ class ICGetPropCallGetter : public ICMonitoredStub outerClass_(outerClass) { MOZ_ASSERT(kind == ICStub::GetProp_CallScripted || - kind == ICStub::GetProp_CallNative); + kind == ICStub::GetProp_CallNative || + kind == ICStub::GetProp_CallNativeGlobal); } }; }; @@ -3042,36 +3071,61 @@ class ICGetProp_CallNative : public ICGetPropCallGetter static ICGetProp_CallNative* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub, ICGetProp_CallNative& other); - class Compiler : public ICGetPropCallGetter::Compiler - { - bool inputDefinitelyObject_; - protected: - bool generateStubCode(MacroAssembler& masm); +}; - virtual int32_t getKey() const { - int32_t baseKey = ICGetPropCallGetter::Compiler::getKey(); - MOZ_ASSERT((baseKey >> 21) == 0); - return baseKey | (static_cast(inputDefinitelyObject_) << 21); - } +// Stub for calling a native getter on the GlobalObject. +class ICGetProp_CallNativeGlobal : public ICGetPropCallGetter +{ + friend class ICStubSpace; - public: - Compiler(JSContext* cx, ICStub* firstMonitorStub, HandleObject receiver, - HandleObject holder, HandleFunction getter, uint32_t pcOffset, - const Class* outerClass, bool inputDefinitelyObject = false) - : ICGetPropCallGetter::Compiler(cx, ICStub::GetProp_CallNative, - firstMonitorStub, receiver, holder, - getter, pcOffset, outerClass), - inputDefinitelyObject_(inputDefinitelyObject) - {} + protected: + HeapPtrShape globalShape_; - ICStub* getStub(ICStubSpace* space) { - ReceiverGuard guard(receiver_); - Shape* holderShape = holder_->as().lastProperty(); - return newStub(space, getStubCode(), firstMonitorStub_, - guard, holder_, holderShape, - getter_, pcOffset_); - } - }; + ICGetProp_CallNativeGlobal(JitCode* stubCode, ICStub* firstMonitorStub, + ReceiverGuard receiverGuard, + JSObject* holder, Shape* holderShape, Shape* globalShape, + JSFunction* getter, uint32_t pcOffset) + : ICGetPropCallGetter(GetProp_CallNativeGlobal, stubCode, firstMonitorStub, + receiverGuard, holder, holderShape, getter, pcOffset), + globalShape_(globalShape) + { } + + public: + static ICGetProp_CallNativeGlobal* Clone(JSContext* cx, ICStubSpace* space, + ICStub* firstMonitorStub, + ICGetProp_CallNativeGlobal& other); + + HeapPtrShape& globalShape() { + return globalShape_; + } + static size_t offsetOfGlobalShape() { + return offsetof(ICGetProp_CallNativeGlobal, globalShape_); + } +}; + +class ICGetPropCallNativeCompiler : public ICGetPropCallGetter::Compiler +{ + bool inputDefinitelyObject_; + protected: + bool generateStubCode(MacroAssembler& masm); + + virtual int32_t getKey() const { + int32_t baseKey = ICGetPropCallGetter::Compiler::getKey(); + MOZ_ASSERT((baseKey >> 21) == 0); + return baseKey | (static_cast(inputDefinitelyObject_) << 21); + } + + public: + ICGetPropCallNativeCompiler(JSContext* cx, ICStub::Kind kind, ICStub* firstMonitorStub, + HandleObject receiver, HandleObject holder, HandleFunction getter, + uint32_t pcOffset, const Class* outerClass, + bool inputDefinitelyObject = false) + : ICGetPropCallGetter::Compiler(cx, kind, firstMonitorStub, receiver, holder, + getter, pcOffset, outerClass), + inputDefinitelyObject_(inputDefinitelyObject) + {} + + ICStub* getStub(ICStubSpace* space); }; class ICGetPropCallDOMProxyNativeStub : public ICGetPropCallGetter diff --git a/js/src/jit/BaselineICList.h b/js/src/jit/BaselineICList.h index 88c0800aed96..1d17e8e2a212 100644 --- a/js/src/jit/BaselineICList.h +++ b/js/src/jit/BaselineICList.h @@ -78,6 +78,7 @@ namespace jit { _(In_Dense) \ \ _(GetName_Fallback) \ + _(GetName_GlobalLexical) \ _(GetName_Global) \ _(GetName_Scope0) \ _(GetName_Scope1) \ @@ -104,6 +105,7 @@ namespace jit { _(GetProp_TypedObject) \ _(GetProp_CallScripted) \ _(GetProp_CallNative) \ + _(GetProp_CallNativeGlobal) \ _(GetProp_CallDOMProxyNative) \ _(GetProp_CallDOMProxyWithGenerationNative) \ _(GetProp_DOMProxyShadowed) \ diff --git a/js/src/jit/JitFrames.cpp b/js/src/jit/JitFrames.cpp index c0df19853487..1c77cfe36cf9 100644 --- a/js/src/jit/JitFrames.cpp +++ b/js/src/jit/JitFrames.cpp @@ -2552,7 +2552,7 @@ InlineFrameIterator::computeScopeChain(Value scopeChainValue, MaybeReadFallback& // the global on their scope chain. MOZ_ASSERT(!script()->isForEval()); MOZ_ASSERT(!script()->hasNonSyntacticScope()); - return &script()->global(); + return &script()->global().lexicalScope(); } bool diff --git a/js/src/jit/SharedIC.cpp b/js/src/jit/SharedIC.cpp index 0d2f187bd9f1..c27150b03e18 100644 --- a/js/src/jit/SharedIC.cpp +++ b/js/src/jit/SharedIC.cpp @@ -366,7 +366,10 @@ ICStub::trace(JSTracer* trc) } case ICStub::GetName_Global: { ICGetName_Global* globalStub = toGetName_Global(); - TraceEdge(trc, &globalStub->shape(), "baseline-global-stub-shape"); + globalStub->receiverGuard().trace(trc); + TraceEdge(trc, &globalStub->holder(), "baseline-global-stub-holder"); + TraceEdge(trc, &globalStub->holderShape(), "baseline-global-stub-holdershape"); + TraceEdge(trc, &globalStub->globalShape(), "baseline-global-stub-globalshape"); break; } case ICStub::GetName_Scope0: @@ -479,6 +482,15 @@ ICStub::trace(JSTracer* trc) TraceEdge(trc, &callStub->getter(), "baseline-getpropcallnative-stub-getter"); break; } + case ICStub::GetProp_CallNativeGlobal: { + ICGetProp_CallNativeGlobal* callStub = toGetProp_CallNativeGlobal(); + callStub->receiverGuard().trace(trc); + TraceEdge(trc, &callStub->holder(), "baseline-getpropcallnativeglobal-stub-holder"); + TraceEdge(trc, &callStub->holderShape(), "baseline-getpropcallnativeglobal-stub-holdershape"); + TraceEdge(trc, &callStub->globalShape(), "baseline-getpropcallnativeglobal-stub-globalshape"); + TraceEdge(trc, &callStub->getter(), "baseline-getpropcallnativeglobal-stub-getter"); + break; + } case ICStub::SetProp_Native: { ICSetProp_Native* propStub = toSetProp_Native(); TraceEdge(trc, &propStub->shape(), "baseline-setpropnative-stub-shape"); diff --git a/js/src/jit/SharedIC.h b/js/src/jit/SharedIC.h index 10189036d1e6..447419514c23 100644 --- a/js/src/jit/SharedIC.h +++ b/js/src/jit/SharedIC.h @@ -720,6 +720,7 @@ class ICStub case GetElem_UnboxedPropertyName: case GetProp_CallScripted: case GetProp_CallNative: + case GetProp_CallNativeGlobal: case GetProp_CallDOMProxyNative: case GetProp_CallDOMProxyWithGenerationNative: case GetProp_DOMProxyShadowed: @@ -737,6 +738,7 @@ class ICStub case GetElem_Arguments: case GetProp_NativePrototype: case GetProp_Native: + case GetName_Global: #endif return true; default: diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 070794fc448f..6f6185b2c510 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -167,25 +167,14 @@ CheckOverRecursedWithExtra(JSContext* cx, BaselineFrame* frame, } bool -DefVarOrConst(JSContext* cx, HandlePropertyName dn, unsigned attrs, HandleObject scopeChain) +DefVar(JSContext* cx, HandlePropertyName dn, unsigned attrs, HandleObject scopeChain) { // Given the ScopeChain, extract the VarObj. RootedObject obj(cx, scopeChain); while (!obj->isQualifiedVarObj()) obj = obj->enclosingScope(); - return DefVarOrConstOperation(cx, obj, dn, attrs); -} - -bool -SetConst(JSContext* cx, HandlePropertyName name, HandleObject scopeChain, HandleValue rval) -{ - // Given the ScopeChain, extract the VarObj. - RootedObject obj(cx, scopeChain); - while (!obj->isQualifiedVarObj()) - obj = obj->enclosingScope(); - - return SetConstOperation(cx, obj, name, rval); + return DefVarOperation(cx, obj, dn, attrs); } bool diff --git a/js/src/jit/VMFunctions.h b/js/src/jit/VMFunctions.h index 291356a9c429..14373f243e9e 100644 --- a/js/src/jit/VMFunctions.h +++ b/js/src/jit/VMFunctions.h @@ -588,8 +588,7 @@ bool CheckOverRecursed(JSContext* cx); bool CheckOverRecursedWithExtra(JSContext* cx, BaselineFrame* frame, uint32_t extra, uint32_t earlyCheck); -bool DefVarOrConst(JSContext* cx, HandlePropertyName dn, unsigned attrs, HandleObject scopeChain); -bool SetConst(JSContext* cx, HandlePropertyName name, HandleObject scopeChain, HandleValue rval); +bool DefVar(JSContext* cx, HandlePropertyName dn, unsigned attrs, HandleObject scopeChain); bool MutatePrototype(JSContext* cx, HandlePlainObject obj, HandleValue value); bool InitProp(JSContext* cx, HandleObject obj, HandlePropertyName name, HandleValue value, jsbytecode* pc); From e168c18e3bb4a0f2c5f45be9461b3c9cfbb95dba Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Tue, 6 Oct 2015 14:00:29 -0700 Subject: [PATCH 086/228] Bug 589199 - Support global lexicals in Ion. (r=jandem) --- js/src/jit/BaselineBailouts.cpp | 12 +-- js/src/jit/BaselineFrameInfo.cpp | 6 +- js/src/jit/BytecodeAnalysis.cpp | 2 - js/src/jit/CodeGenerator.cpp | 19 ++++- js/src/jit/CodeGenerator.h | 1 + js/src/jit/CompileInfo.h | 2 +- js/src/jit/IonBuilder.cpp | 124 ++++++++++++++++++++++++---- js/src/jit/IonBuilder.h | 3 + js/src/jit/IonCaches.cpp | 16 +++- js/src/jit/JitFrames.h | 6 ++ js/src/jit/Lowering.cpp | 8 ++ js/src/jit/Lowering.h | 1 + js/src/jit/MIR.h | 27 ++++++ js/src/jit/MOpcodes.h | 1 + js/src/jit/shared/LIR-shared.h | 10 +++ js/src/jit/shared/LOpcodes-shared.h | 1 + 16 files changed, 203 insertions(+), 36 deletions(-) diff --git a/js/src/jit/BaselineBailouts.cpp b/js/src/jit/BaselineBailouts.cpp index 21addacab025..d6bdea5b2868 100644 --- a/js/src/jit/BaselineBailouts.cpp +++ b/js/src/jit/BaselineBailouts.cpp @@ -706,14 +706,14 @@ InitFromBailout(JSContext* cx, HandleScript caller, jsbytecode* callerPC, } } else { // For global scripts without a non-syntactic scope the scope - // chain is the script's global (Ion does not compile scripts - // with a non-syntactic global scope). Also note that it's - // invalid to resume into the prologue in this case because - // the prologue expects the scope chain in R1 for eval and - // global scripts. + // chain is the script's global lexical scope (Ion does not + // compile scripts with a non-syntactic global scope). Also + // note that it's invalid to resume into the prologue in this + // case because the prologue expects the scope chain in R1 for + // eval and global scripts. MOZ_ASSERT(!script->isForEval()); MOZ_ASSERT(!script->hasNonSyntacticScope()); - scopeChain = &(script->global()); + scopeChain = &(script->global().lexicalScope()); } } diff --git a/js/src/jit/BaselineFrameInfo.cpp b/js/src/jit/BaselineFrameInfo.cpp index 535e0d33d947..e285656a96f7 100644 --- a/js/src/jit/BaselineFrameInfo.cpp +++ b/js/src/jit/BaselineFrameInfo.cpp @@ -16,11 +16,7 @@ using namespace js::jit; bool FrameInfo::init(TempAllocator& alloc) { - // The minimum stack size is two. One slot is always needed for - // this/arguments type checks. Two slots are needed because INITGLEXICAL - // (stack depth 1) is compiled as a SETPROP (stack depth 2) on the global - // lexical scope. - size_t nstack = Max(script->nslots() - script->nfixed(), size_t(2)); + size_t nstack = Max(script->nslots() - script->nfixed(), size_t(MinJITStackSize)); if (!stack.init(alloc, nstack)) return false; diff --git a/js/src/jit/BytecodeAnalysis.cpp b/js/src/jit/BytecodeAnalysis.cpp index 339853ea8143..6374262e210e 100644 --- a/js/src/jit/BytecodeAnalysis.cpp +++ b/js/src/jit/BytecodeAnalysis.cpp @@ -167,8 +167,6 @@ BytecodeAnalysis::init(TempAllocator& alloc, GSNCache& gsn) case JSOP_LAMBDA_ARROW: case JSOP_DEFFUN: case JSOP_DEFVAR: - case JSOP_DEFCONST: - case JSOP_SETCONST: usesScopeChain_ = true; break; diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 2e68247061b6..6cf16cff7add 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -3713,9 +3713,8 @@ CodeGenerator::visitCheckOverRecursed(LCheckOverRecursed* lir) masm.bind(ool->rejoin()); } -typedef bool (*DefVarOrConstFn)(JSContext*, HandlePropertyName, unsigned, HandleObject); -static const VMFunction DefVarOrConstInfo = - FunctionInfo(DefVarOrConst); +typedef bool (*DefVarFn)(JSContext*, HandlePropertyName, unsigned, HandleObject); +static const VMFunction DefVarInfo = FunctionInfo(DefVar); void CodeGenerator::visitDefVar(LDefVar* lir) @@ -3726,7 +3725,19 @@ CodeGenerator::visitDefVar(LDefVar* lir) pushArg(Imm32(lir->mir()->attrs())); // unsigned pushArg(ImmGCPtr(lir->mir()->name())); // PropertyName* - callVM(DefVarOrConstInfo, lir); + callVM(DefVarInfo, lir); +} + +typedef bool (*DefLexicalFn)(JSContext*, HandlePropertyName, unsigned); +static const VMFunction DefLexicalInfo = FunctionInfo(DefLexicalOperation); + +void +CodeGenerator::visitDefLexical(LDefLexical* lir) +{ + pushArg(Imm32(lir->mir()->attrs())); // unsigned + pushArg(ImmGCPtr(lir->mir()->name())); // PropertyName* + + callVM(DefLexicalInfo, lir); } typedef bool (*DefFunOperationFn)(JSContext*, HandleScript, HandleObject, HandleFunction); diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h index 547b4c526709..0ba843cca381 100644 --- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -73,6 +73,7 @@ class CodeGenerator : public CodeGeneratorSpecific void visitStart(LStart* lir); void visitReturn(LReturn* ret); void visitDefVar(LDefVar* lir); + void visitDefLexical(LDefLexical* lir); void visitDefFun(LDefFun* lir); void visitOsrEntry(LOsrEntry* lir); void visitOsrScopeChain(LOsrScopeChain* lir); diff --git a/js/src/jit/CompileInfo.h b/js/src/jit/CompileInfo.h index 7fd299950c6e..70df46e9523d 100644 --- a/js/src/jit/CompileInfo.h +++ b/js/src/jit/CompileInfo.h @@ -221,7 +221,7 @@ class CompileInfo nbodyfixed_ = script->nbodyfixed(); nlocals_ = script->nfixed(); fixedLexicalBegin_ = script->fixedLexicalBegin(); - nstack_ = script->nslots() - script->nfixed(); + nstack_ = Max(script->nslots() - script->nfixed(), MinJITStackSize); nslots_ = nimplicit_ + nargs_ + nlocals_ + nstack_; } diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 9dd58efe9e1a..c518e7b6062e 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -1235,10 +1235,10 @@ IonBuilder::initScopeChain(MDefinition* callee) scope = constant(ObjectValue(module->initialEnvironment())); } else { // For global scripts without a non-syntactic global scope, the scope - // chain is the global object. + // chain is the global lexical scope. MOZ_ASSERT(!script()->isForEval()); MOZ_ASSERT(!script()->hasNonSyntacticScope()); - scope = constant(ObjectValue(script()->global())); + scope = constant(ObjectValue(script()->global().lexicalScope())); } current->setScopeChain(scope); @@ -1675,9 +1675,12 @@ IonBuilder::inspectOpcode(JSOp op) return jsop_andor(op); case JSOP_DEFVAR: - case JSOP_DEFCONST: return jsop_defvar(GET_UINT32_INDEX(pc)); + case JSOP_DEFLET: + case JSOP_DEFCONST: + return jsop_deflexical(GET_UINT32_INDEX(pc)); + case JSOP_DEFFUN: return jsop_deffun(GET_UINT32_INDEX(pc)); @@ -1764,6 +1767,13 @@ IonBuilder::inspectOpcode(JSOp op) current->setLocal(GET_LOCALNO(pc)); return true; + case JSOP_INITGLEXICAL: { + MDefinition* value = current->pop(); + current->push(constant(ObjectValue(script()->global().lexicalScope()))); + current->push(value); + return jsop_setprop(info().getAtom(pc)->asPropertyName()); + } + case JSOP_CHECKALIASEDLEXICAL: return jsop_checkaliasedlet(ScopeCoordinate(pc)); @@ -1870,7 +1880,7 @@ IonBuilder::inspectOpcode(JSOp op) PropertyName* name = info().getAtom(pc)->asPropertyName(); if (script()->hasNonSyntacticScope()) return jsop_setprop(name); - JSObject* obj = &script()->global(); + JSObject* obj = testGlobalLexicalBinding(name); return setStaticName(obj, name); } @@ -1887,8 +1897,10 @@ IonBuilder::inspectOpcode(JSOp op) } case JSOP_BINDGNAME: - if (!script()->hasNonSyntacticScope()) - return pushConstant(ObjectValue(script()->global())); + if (!script()->hasNonSyntacticScope()) { + JSObject* scope = testGlobalLexicalBinding(info().getName(pc)); + return pushConstant(ObjectValue(*scope)); + } // Fall through to JSOP_BINDNAME case JSOP_BINDNAME: return jsop_bindname(info().getName(pc)); @@ -7945,6 +7957,17 @@ NumFixedSlots(JSObject* object) return gc::GetGCKindSlots(kind, object->getClass()); } +static bool +IsUninitializedGlobalLexicalSlot(JSObject* obj, PropertyName* name) +{ + ClonedBlockObject &globalLexical = obj->as(); + MOZ_ASSERT(globalLexical.isGlobal()); + Shape* shape = globalLexical.lookupPure(name); + if (!shape) + return false; + return globalLexical.getSlot(shape->slot()).isMagic(JS_UNINITIALIZED_LEXICAL); +} + bool IonBuilder::getStaticName(JSObject* staticObject, PropertyName* name, bool* psucceeded, MDefinition* lexicalCheck) @@ -7953,7 +7976,11 @@ IonBuilder::getStaticName(JSObject* staticObject, PropertyName* name, bool* psuc jsid id = NameToId(name); - MOZ_ASSERT(staticObject->is() || staticObject->is()); + bool isGlobalLexical = staticObject->is() && + staticObject->as().isGlobal(); + MOZ_ASSERT(isGlobalLexical || + staticObject->is() || + staticObject->is()); MOZ_ASSERT(staticObject->isSingleton()); *psucceeded = true; @@ -8000,6 +8027,13 @@ IonBuilder::getStaticName(JSObject* staticObject, PropertyName* name, bool* psuc return true; } + // Don't optimize global lexical bindings if they aren't initialized at + // compile time. + if (isGlobalLexical && IsUninitializedGlobalLexicalSlot(staticObject, name)) { + *psucceeded = false; + return true; + } + TemporaryTypeSet* types = bytecodeTypes(pc); BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), staticKey, name, types, /* updateObserved = */ true); @@ -8055,7 +8089,11 @@ IonBuilder::setStaticName(JSObject* staticObject, PropertyName* name) { jsid id = NameToId(name); - MOZ_ASSERT(staticObject->is() || staticObject->is()); + bool isGlobalLexical = staticObject->is() && + staticObject->as().isGlobal(); + MOZ_ASSERT(isGlobalLexical || + staticObject->is() || + staticObject->is()); MDefinition* value = current->peek(-1); @@ -8077,6 +8115,11 @@ IonBuilder::setStaticName(JSObject* staticObject, PropertyName* name) if (!CanWriteProperty(alloc(), constraints(), property, value)) return jsop_setprop(name); + // Don't optimize global lexical bindings if they aren't initialized at + // compile time. + if (isGlobalLexical && IsUninitializedGlobalLexicalSlot(staticObject, name)) + return jsop_setprop(name); + current->pop(); // Pop the bound object on the stack. @@ -8098,10 +8141,47 @@ IonBuilder::setStaticName(JSObject* staticObject, PropertyName* name) value, needsBarrier, slotType); } +JSObject* +IonBuilder::testGlobalLexicalBinding(PropertyName* name) +{ + MOZ_ASSERT(JSOp(*pc) == JSOP_BINDGNAME || + JSOp(*pc) == JSOP_GETGNAME || + JSOp(*pc) == JSOP_SETGNAME || + JSOp(*pc) == JSOP_STRICTSETGNAME); + + // The global isn't the global lexical scope's prototype, but its + // enclosing scope. Test for the existence of |name| manually on the + // global lexical scope. If it is not found, look for it on the global + // itself. + + NativeObject* obj = &script()->global().lexicalScope(); + TypeSet::ObjectKey* lexicalKey = TypeSet::ObjectKey::get(obj); + jsid id = NameToId(name); + if (analysisContext) + lexicalKey->ensureTrackedProperty(analysisContext, id); + if (!lexicalKey->unknownProperties()) { + // If the property is not found on the global lexical scope but it is + // found on the global and is configurable, freeze the typeset for its + // non-existence. + // + // In the case that it is found on the global but is non-configurable, + // the binding cannot be shadowed by a global lexical binding. + HeapTypeSetKey lexicalProperty = lexicalKey->property(id); + if (!obj->containsPure(name)) { + Shape* shape = script()->global().lookupPure(name); + if (!shape || !shape->configurable()) + MOZ_ALWAYS_FALSE(lexicalProperty.isOwnProperty(constraints())); + obj = &script()->global(); + } + } + + return obj; +} + bool IonBuilder::jsop_getgname(PropertyName* name) { - JSObject* obj = &script()->global(); + JSObject* obj = testGlobalLexicalBinding(name); bool emitted = false; if (!getStaticName(obj, name, &emitted) || emitted) return emitted; @@ -8121,7 +8201,7 @@ IonBuilder::jsop_getname(PropertyName* name) { MDefinition* object; if (IsGlobalOp(JSOp(*pc)) && !script()->hasNonSyntacticScope()) { - MInstruction* global = constant(ObjectValue(script()->global())); + MInstruction* global = constant(ObjectValue(script()->global().lexicalScope())); object = global; } else { current->push(current->scopeChain()); @@ -12560,16 +12640,12 @@ IonBuilder::jsop_setarg(uint32_t arg) bool IonBuilder::jsop_defvar(uint32_t index) { - MOZ_ASSERT(JSOp(*pc) == JSOP_DEFVAR || JSOp(*pc) == JSOP_DEFCONST); + MOZ_ASSERT(JSOp(*pc) == JSOP_DEFVAR); PropertyName* name = script()->getName(index); // Bake in attrs. - unsigned attrs = JSPROP_ENUMERATE; - if (JSOp(*pc) == JSOP_DEFCONST) - attrs |= JSPROP_READONLY; - else - attrs |= JSPROP_PERMANENT; + unsigned attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT; MOZ_ASSERT(!script()->isForEval()); // Pass the ScopeChain. @@ -12582,6 +12658,22 @@ IonBuilder::jsop_defvar(uint32_t index) return resumeAfter(defvar); } +bool +IonBuilder::jsop_deflexical(uint32_t index) +{ + MOZ_ASSERT(JSOp(*pc) == JSOP_DEFLET || JSOp(*pc) == JSOP_DEFCONST); + + PropertyName* name = script()->getName(index); + unsigned attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT; + if (JSOp(*pc) == JSOP_DEFCONST) + attrs |= JSPROP_READONLY; + + MDefLexical* deflex = MDefLexical::New(alloc(), name, attrs); + current->add(deflex); + + return resumeAfter(deflex); +} + bool IonBuilder::jsop_deffun(uint32_t index) { diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index 58868fac6e70..4cc6544ef878 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -652,6 +652,7 @@ class IonBuilder bool jsop_tostring(); bool jsop_setarg(uint32_t arg); bool jsop_defvar(uint32_t index); + bool jsop_deflexical(uint32_t index); bool jsop_deffun(uint32_t index); bool jsop_notearg(); bool jsop_checklexical(); @@ -961,6 +962,8 @@ class IonBuilder MGetPropertyCache* getInlineableGetPropertyCache(CallInfo& callInfo); + JSObject* testGlobalLexicalBinding(PropertyName* name); + JSObject* testSingletonProperty(JSObject* obj, jsid id); JSObject* testSingletonPropertyTypes(MDefinition* obj, jsid id); diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index e2d005aeb08e..84dc42ea6c1e 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -1092,6 +1092,11 @@ GenerateCallGetter(JSContext* cx, IonScript* ion, MacroAssembler& masm, Label pop1AndFail; Label* maybePopAndFail = failures; + // If we're calling a getter on the global, inline the logic for the + // 'this' hook on the global lexical scope and manually push the global. + if (IsGlobalLexicalScope(obj)) + masm.extractObject(Address(object, ScopeObject::offsetOfEnclosingScope()), object); + // Save off the object register if it aliases the scratchReg if (spillObjReg) { masm.push(object); @@ -3332,8 +3337,15 @@ SetPropertyIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex } // Set/Add the property on the object, the inlined cache are setup for the next execution. - if (!SetProperty(cx, obj, name, value, cache.strict(), cache.pc())) - return false; + if (JSOp(*cache.pc()) == JSOP_INITGLEXICAL) { + RootedScript script(cx); + jsbytecode* pc; + cache.getScriptedLocation(&script, &pc); + InitGlobalLexicalOperation(cx, script, pc, value); + } else { + if (!SetProperty(cx, obj, name, value, cache.strict(), cache.pc())) + return false; + } // A GC may have caused cache.value() to become stale as it is not traced. // In this case the IonScript will have been invalidated, so check for that. diff --git a/js/src/jit/JitFrames.h b/js/src/jit/JitFrames.h index 397ff3916bd0..21e27b701464 100644 --- a/js/src/jit/JitFrames.h +++ b/js/src/jit/JitFrames.h @@ -1000,6 +1000,12 @@ GetPcScript(JSContext* cx, JSScript** scriptRes, jsbytecode** pcRes); CalleeToken MarkCalleeToken(JSTracer* trc, CalleeToken token); +// The minimum stack size is two. Two slots are needed because INITGLEXICAL +// (stack depth 1) is compiled as a SETPROP (stack depth 2) on the global +// lexical scope. Baseline also requires one slot for this/argument type +// checks. +static const uint32_t MinJITStackSize = 2; + } /* namespace jit */ } /* namespace js */ diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index bae8688a4434..f65595faa450 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -153,6 +153,14 @@ LIRGenerator::visitDefVar(MDefVar* ins) assignSafepoint(lir, ins); } +void +LIRGenerator::visitDefLexical(MDefLexical* ins) +{ + LDefLexical* lir = new(alloc()) LDefLexical(); + add(lir, ins); + assignSafepoint(lir, ins); +} + void LIRGenerator::visitDefFun(MDefFun* ins) { diff --git a/js/src/jit/Lowering.h b/js/src/jit/Lowering.h index ffcdba8b2684..4e03c5ef56d5 100644 --- a/js/src/jit/Lowering.h +++ b/js/src/jit/Lowering.h @@ -88,6 +88,7 @@ class LIRGenerator : public LIRGeneratorSpecific void visitInitPropGetterSetter(MInitPropGetterSetter* ins); void visitCheckOverRecursed(MCheckOverRecursed* ins); void visitDefVar(MDefVar* ins); + void visitDefLexical(MDefLexical* ins); void visitDefFun(MDefFun* ins); void visitCreateThisWithTemplate(MCreateThisWithTemplate* ins); void visitCreateThisWithProto(MCreateThisWithProto* ins); diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 40779372ce96..89c2191eb13a 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -7318,6 +7318,33 @@ class MDefVar } }; +class MDefLexical + : public MNullaryInstruction +{ + CompilerPropertyName name_; // Target name to be defined. + unsigned attrs_; // Attributes to be set. + + private: + MDefLexical(PropertyName* name, unsigned attrs) + : name_(name), + attrs_(attrs) + { } + + public: + INSTRUCTION_HEADER(DefLexical) + + static MDefLexical* New(TempAllocator& alloc, PropertyName* name, unsigned attrs) { + return new(alloc) MDefLexical(name, attrs); + } + + PropertyName* name() const { + return name_; + } + unsigned attrs() const { + return attrs_; + } +}; + class MDefFun : public MUnaryInstruction, public NoTypePolicy::Data diff --git a/js/src/jit/MOpcodes.h b/js/src/jit/MOpcodes.h index 2d196464420b..530d70ee42f3 100644 --- a/js/src/jit/MOpcodes.h +++ b/js/src/jit/MOpcodes.h @@ -53,6 +53,7 @@ namespace jit { _(UnarySharedStub) \ _(CheckOverRecursed) \ _(DefVar) \ + _(DefLexical) \ _(DefFun) \ _(CreateThis) \ _(CreateThisWithProto) \ diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h index 56f5416d97eb..c69e3160ba6f 100644 --- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -1228,6 +1228,16 @@ class LDefVar : public LCallInstructionHelper<0, 1, 0> } }; +class LDefLexical : public LCallInstructionHelper<0, 0, 0> +{ + public: + LIR_HEADER(DefLexical) + + MDefLexical* mir() const { + return mir_->toDefLexical(); + } +}; + class LDefFun : public LCallInstructionHelper<0, 1, 0> { public: diff --git a/js/src/jit/shared/LOpcodes-shared.h b/js/src/jit/shared/LOpcodes-shared.h index 6da3fd1a268f..a3ceea33e71f 100644 --- a/js/src/jit/shared/LOpcodes-shared.h +++ b/js/src/jit/shared/LOpcodes-shared.h @@ -68,6 +68,7 @@ _(InitPropGetterSetter) \ _(CheckOverRecursed) \ _(DefVar) \ + _(DefLexical) \ _(DefFun) \ _(CallKnown) \ _(CallGeneric) \ From df3a5245f4ccd12188449761c3e564f006b7b482 Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Tue, 6 Oct 2015 14:00:29 -0700 Subject: [PATCH 087/228] Bug 589199 - Fix eval static scope to play with the global lexical scope. (r=efaust) --- js/src/builtin/Eval.cpp | 9 ++++++--- js/src/frontend/BytecodeCompiler.cpp | 7 +++++-- js/src/frontend/BytecodeEmitter.cpp | 11 ++++++++--- js/src/jit-test/tests/basic/eval-scopes.js | 10 ++++------ js/src/jit/BaselineFrame.cpp | 4 ++-- js/src/jit/BaselineFrame.h | 4 ++-- js/src/jsapi.cpp | 2 +- js/src/jsscript.cpp | 3 ++- js/src/vm/ScopeObject.h | 15 +++++++++------ js/src/vm/Stack.cpp | 6 +++--- js/src/vm/Stack.h | 4 ++-- 11 files changed, 44 insertions(+), 31 deletions(-) diff --git a/js/src/builtin/Eval.cpp b/js/src/builtin/Eval.cpp index 59fb11156063..85fb4bdd6c3b 100644 --- a/js/src/builtin/Eval.cpp +++ b/js/src/builtin/Eval.cpp @@ -229,7 +229,7 @@ EvalKernel(JSContext* cx, const CallArgs& args, EvalType evalType, AbstractFrame { MOZ_ASSERT((evalType == INDIRECT_EVAL) == !caller); MOZ_ASSERT((evalType == INDIRECT_EVAL) == !pc); - MOZ_ASSERT_IF(evalType == INDIRECT_EVAL, scopeobj->is()); + MOZ_ASSERT_IF(evalType == INDIRECT_EVAL, IsGlobalLexicalScope(scopeobj)); AssertInnerizedScopeChain(cx, *scopeobj); Rooted scopeObjGlobal(cx, &scopeobj->global()); @@ -271,7 +271,7 @@ EvalKernel(JSContext* cx, const CallArgs& args, EvalType evalType, AbstractFrame return false; thisv = caller.thisValue(); } else { - MOZ_ASSERT(args.callee().global() == *scopeobj); + MOZ_ASSERT(args.callee().global() == scopeobj->as().global()); // Use the global as 'this', modulo outerization. JSObject* thisobj = GetThisObject(cx, scopeobj); @@ -313,6 +313,8 @@ EvalKernel(JSContext* cx, const CallArgs& args, EvalType evalType, AbstractFrame RootedObject enclosing(cx); if (evalType == DIRECT_EVAL) enclosing = callerScript->innermostStaticScope(pc); + else + enclosing = &cx->global()->lexicalScope().staticBlock(); Rooted staticScope(cx, StaticEvalObject::create(cx, enclosing)); if (!staticScope) return false; @@ -454,7 +456,8 @@ js::IndirectEval(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); Rooted global(cx, &args.callee().global()); - return EvalKernel(cx, args, INDIRECT_EVAL, NullFramePtr(), global, nullptr); + RootedObject globalLexical(cx, &global->lexicalScope()); + return EvalKernel(cx, args, INDIRECT_EVAL, NullFramePtr(), globalLexical, nullptr); } bool diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index 6623743a9860..aebaf8e4dee5 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -287,8 +287,11 @@ BytecodeCompiler::isEvalCompilationUnit() bool BytecodeCompiler::isNonGlobalEvalCompilationUnit() { - return isEvalCompilationUnit() && - enclosingStaticScope->as().enclosingScopeForStaticScopeIter(); + if (!isEvalCompilationUnit()) + return false; + StaticEvalObject& eval = enclosingStaticScope->as(); + JSObject* enclosing = eval.enclosingScopeForStaticScopeIter(); + return !IsStaticGlobalLexicalScope(enclosing); } bool diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 088b61e12f75..01f6c3ddc3db 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -1537,9 +1537,14 @@ BytecodeEmitter::tryConvertFreeName(ParseNode* pn) FunctionBox* funbox = sc->asFunctionBox(); PropertyName* name = pn->pn_atom->asPropertyName(); for (StaticScopeIter ssi(funbox->staticScope()); !ssi.done(); ssi++) { - // Don't optimize names through eval. - if (ssi.type() == StaticScopeIter::Eval) - return false; + // Don't optimize names through non-global eval. For global eval + // we can use GNAME ops. + if (ssi.type() == StaticScopeIter::Eval) { + if (ssi.eval().isNonGlobal()) + return false; + MOZ_ASSERT(!slot.isSome()); + break; + } if (!ssi.hasSyntacticDynamicScopeObject()) continue; diff --git a/js/src/jit-test/tests/basic/eval-scopes.js b/js/src/jit-test/tests/basic/eval-scopes.js index 1a9aa6374437..1342ef564a2c 100644 --- a/js/src/jit-test/tests/basic/eval-scopes.js +++ b/js/src/jit-test/tests/basic/eval-scopes.js @@ -50,16 +50,14 @@ setLazyParsingDisabled(false); eval("function h() { assertEq(x, 'inner');} h()"); eval("function h2() { (function nest() { assertEq(x, 'inner'); })(); } h2()"); } -// It sure would be nice if we could run the h3/h4 tests below, but it turns out -// that lazy functions and eval don't play together all that well. See bug -// 1146080. For now, assert we have no gname, so people will notice if they -// accidentally fix it and adjust this test accordingly. + +// GNAME optimizations should work through lazy parsing. eval(` function h3() { assertEq(x, 'outer'); } h3(); - hasGname(h3, 'x', false); + hasGname(h3, 'x', true); `); eval(` function h4() { @@ -67,7 +65,7 @@ eval(` nest(); return nest; } - hasGname(h4(), 'x', false); + hasGname(h4(), 'x', true); `); setLazyParsingDisabled(true); diff --git a/js/src/jit/BaselineFrame.cpp b/js/src/jit/BaselineFrame.cpp index 8b87be0da869..10d4db0133d8 100644 --- a/js/src/jit/BaselineFrame.cpp +++ b/js/src/jit/BaselineFrame.cpp @@ -88,10 +88,10 @@ BaselineFrame::trace(JSTracer* trc, JitFrameIterator& frameIterator) } bool -BaselineFrame::isDirectEvalFrame() const +BaselineFrame::isNonGlobalEvalFrame() const { return isEvalFrame() && - script()->enclosingStaticScope()->as().isDirect(); + script()->enclosingStaticScope()->as().isNonGlobal(); } bool diff --git a/js/src/jit/BaselineFrame.h b/js/src/jit/BaselineFrame.h index 291259a80e6d..8a3dadb55611 100644 --- a/js/src/jit/BaselineFrame.h +++ b/js/src/jit/BaselineFrame.h @@ -408,9 +408,9 @@ class BaselineFrame bool isNonStrictEvalFrame() const { return isEvalFrame() && !script()->strict(); } - bool isDirectEvalFrame() const; + bool isNonGlobalEvalFrame() const; bool isNonStrictDirectEvalFrame() const { - return isNonStrictEvalFrame() && isDirectEvalFrame(); + return isNonStrictEvalFrame() && isNonGlobalEvalFrame(); } bool isNonEvalFunctionFrame() const { return isFunctionFrame() && !isEvalFrame(); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index c341a4d97064..1e4e5861b44f 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3486,7 +3486,7 @@ IsFunctionCloneable(HandleFunction fun) // If the script is an indirect eval that is immediately scoped // under the global, we can clone it. if (enclosing->is()) - return !enclosing->as().isDirect(); + return !enclosing->as().isNonGlobal(); // If the script already deals with a non-syntactic scope, we can // clone it. diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 0b7fdec03f07..55cb5abb3298 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -3309,7 +3309,8 @@ js::detail::CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScri RootedObject enclosingScope(cx); if (NestedScopeObject* enclosingBlock = innerBlock->enclosingNestedScope()) { if (IsStaticGlobalLexicalScope(enclosingBlock)) { - MOZ_ASSERT(IsStaticGlobalLexicalScope(scriptStaticScope)); + MOZ_ASSERT(IsStaticGlobalLexicalScope(scriptStaticScope) || + scriptStaticScope->is()); enclosingScope = scriptStaticScope; } else { enclosingScope = objects[FindScopeObjectIndex(src, *enclosingBlock)]; diff --git a/js/src/vm/ScopeObject.h b/js/src/vm/ScopeObject.h index b9df7fe09dd8..41661e2e6c85 100644 --- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -456,12 +456,7 @@ class StaticEvalObject : public ScopeObject return getReservedSlot(STRICT_SLOT).isTrue(); } - // Indirect evals terminate in the global at run time, and has no static - // enclosing scope. - bool isDirect() const { - MOZ_ASSERT_IF(!getReservedSlot(SCOPE_CHAIN_SLOT).isObject(), !isStrict()); - return getReservedSlot(SCOPE_CHAIN_SLOT).isObject(); - } + inline bool isNonGlobal() const; }; // Static scope objects that stand in for one or more "polluting global" @@ -1215,6 +1210,14 @@ NestedScopeObject::enclosingNestedScope() const return obj && obj->is() ? &obj->as() : nullptr; } +inline bool +StaticEvalObject::isNonGlobal() const +{ + if (isStrict()) + return true; + return !IsStaticGlobalLexicalScope(&getReservedSlot(SCOPE_CHAIN_SLOT).toObject()); +} + inline bool ScopeIter::done() const { diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 64d4b506b483..8c5c98950262 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -109,10 +109,10 @@ InterpreterFrame::initExecuteFrame(JSContext* cx, HandleScript script, AbstractF } bool -InterpreterFrame::isDirectEvalFrame() const +InterpreterFrame::isNonGlobalEvalFrame() const { return isEvalFrame() && - script()->enclosingStaticScope()->as().isDirect(); + script()->enclosingStaticScope()->as().isNonGlobal(); } bool @@ -259,7 +259,7 @@ InterpreterFrame::epilogue(JSContext* cx) MOZ_ASSERT_IF(hasCallObj(), scopeChain()->as().isForEval()); if (MOZ_UNLIKELY(cx->compartment()->isDebuggee())) DebugScopes::onPopStrictEvalScope(this); - } else if (isDirectEvalFrame()) { + } else if (isNonGlobalEvalFrame()) { MOZ_ASSERT_IF(isDebuggerEvalFrame(), !IsSyntacticScope(scopeChain())); } return; diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index 655e06f7f0e9..92f619f81f40 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -515,10 +515,10 @@ class InterpreterFrame return isEvalFrame() && !script()->strict(); } - bool isDirectEvalFrame() const; + bool isNonGlobalEvalFrame() const; bool isNonStrictDirectEvalFrame() const { - return isNonStrictEvalFrame() && isDirectEvalFrame(); + return isNonStrictEvalFrame() && isNonGlobalEvalFrame(); } /* From 819c2c5120e238823e81a69d60452444ddbd2aef Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Tue, 6 Oct 2015 14:00:29 -0700 Subject: [PATCH 088/228] Bug 589199 - Fix up the global lexical scope when merging off-thread compiled scripts. (r=bhackett) --- js/src/jsgc.cpp | 23 +++++++++++++++++++++++ js/src/jsscript.cpp | 14 ++++++++++++++ js/src/jsscript.h | 9 +++++++++ js/src/vm/HelperThreads.cpp | 8 ++++---- 4 files changed, 50 insertions(+), 4 deletions(-) diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 6eb74ceea6c1..8c480749edeb 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -6745,6 +6745,14 @@ gc::MergeCompartments(JSCompartment* source, JSCompartment* target) MOZ_ASSERT(script->compartment() == source); script->compartment_ = target; script->setTypesGeneration(target->zone()->types.generation); + + // See warning in handleParseWorkload. If we start optimizing global + // lexicals, we would need to merge the contents of the static global + // lexical scope. + if (JSObject* enclosing = script->enclosingStaticScope()) { + if (IsStaticGlobalLexicalScope(enclosing)) + script->fixEnclosingStaticGlobalLexicalScope(); + } } for (ZoneCellIter iter(source->zone(), AllocKind::BASE_SHAPE); !iter.done(); iter.next()) { @@ -6774,6 +6782,21 @@ gc::MergeCompartments(JSCompartment* source, JSCompartment* target) } } + // After fixing JSFunctions' compartments, we can fix LazyScripts' + // enclosing scopes. + for (ZoneCellIter iter(source->zone(), AllocKind::LAZY_SCRIPT); !iter.done(); iter.next()) { + LazyScript* lazy = iter.get(); + MOZ_ASSERT(lazy->functionNonDelazifying()->compartment() == target); + + // See warning in handleParseWorkload. If we start optimizing global + // lexicals, we would need to merge the contents of the static global + // lexical scope. + if (JSObject* enclosing = lazy->enclosingScope()) { + if (IsStaticGlobalLexicalScope(enclosing)) + lazy->fixEnclosingStaticGlobalLexicalScope(); + } + } + // The source should be the only compartment in its zone. for (CompartmentsInZoneIter c(source->zone()); !c.done(); c.next()) MOZ_ASSERT(c.get() == source); diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 55cb5abb3298..70f64b45da1d 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -2946,6 +2946,20 @@ JSScript::uninlinedGlobal() const return global(); } +void +JSScript::fixEnclosingStaticGlobalLexicalScope() +{ + MOZ_ASSERT(IsStaticGlobalLexicalScope(enclosingStaticScope_)); + enclosingStaticScope_ = &global().lexicalScope().staticBlock(); +} + +void +LazyScript::fixEnclosingStaticGlobalLexicalScope() +{ + MOZ_ASSERT(IsStaticGlobalLexicalScope(enclosingScope_)); + enclosingScope_ = &function_->global().lexicalScope().staticBlock(); +} + void JSScript::finalize(FreeOp* fop) { diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 6688df2c9cbd..244070fc6633 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -1644,6 +1644,10 @@ class JSScript : public js::gc::TenuredCell return enclosingStaticScope_; } + // Switch the script over from the off-thread compartment's static + // global lexical scope to the main thread compartment's. + void fixEnclosingStaticGlobalLexicalScope(); + private: bool makeTypes(JSContext* cx); @@ -2186,6 +2190,11 @@ class LazyScript : public gc::TenuredCell JSObject* enclosingScope() const { return enclosingScope_; } + + // Switch the script over from the off-thread compartment's static + // global lexical scope to the main thread compartment's. + void fixEnclosingStaticGlobalLexicalScope(); + ScriptSourceObject* sourceObject() const; ScriptSource* scriptSource() const { return sourceObject()->source(); diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index beb46ed4c9ca..d6980801352f 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -1396,16 +1396,16 @@ HelperThread::handleParseWorkload() // ! WARNING WARNING WARNING ! // // See comment in Parser::bindLexical about optimizing global lexical - // bindings. If we start optimizing them, passing in parseTask->cx's + // bindings. If we start optimizing them, passing in task->cx's // global lexical scope would be incorrect! // // ! WARNING WARNING WARNING ! - ExclusiveContext* parseCx = parseTask->cx; + ExclusiveContext* parseCx = task->cx; Rooted globalLexical(parseCx, &parseCx->global()->lexicalScope()); Rooted staticScope(parseCx, &globalLexical->staticBlock()); - task->script = frontend::CompileScript(parseCx, &parseTask->alloc, + task->script = frontend::CompileScript(parseCx, &task->alloc, globalLexical, staticScope, nullptr, - parseTask->options, srcBuf, + task->options, srcBuf, /* source_ = */ nullptr, /* extraSct = */ nullptr, /* sourceObjectOut = */ &(task->sourceObject)); From 76da4d111237e1a8d9ae5db6b0fd2664aa6d4bc5 Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Tue, 6 Oct 2015 14:00:29 -0700 Subject: [PATCH 089/228] Bug 1202902 - Support non-syntactic extensible lexical scopes. (r=billm) --- js/public/MemoryMetrics.h | 3 +- js/src/builtin/Eval.cpp | 15 +- js/src/builtin/TestingFunctions.cpp | 24 ++- ...NewScript-ExecuteInGlobalAndReturnScope.js | 6 +- js/src/jit/BaselineCompiler.cpp | 7 +- js/src/jit/BaselineIC.cpp | 7 +- js/src/jit/CodeGenerator.cpp | 2 +- js/src/jit/IonBuilder.cpp | 2 + js/src/jit/IonCaches.cpp | 3 +- js/src/jit/VMFunctions.cpp | 21 +++ js/src/jit/VMFunctions.h | 2 + js/src/jsapi.cpp | 37 ++++ js/src/jsapi.h | 9 + js/src/jscompartment.cpp | 52 +++++- js/src/jscompartment.h | 16 +- js/src/jsfriendapi.h | 9 +- js/src/vm/Debugger.cpp | 13 +- js/src/vm/Interpreter-inl.h | 30 ++-- js/src/vm/Interpreter.cpp | 18 +- js/src/vm/MemoryMetrics.cpp | 3 +- js/src/vm/ScopeObject-inl.h | 8 + js/src/vm/ScopeObject.cpp | 48 ++++- js/src/vm/ScopeObject.h | 166 +++++++++++++++--- js/src/vm/Stack-inl.h | 8 +- js/src/vm/Stack.cpp | 6 +- js/src/vm/Stack.h | 4 +- js/src/vm/TypeInference.cpp | 6 +- js/xpconnect/loader/mozJSComponentLoader.cpp | 59 ++++++- js/xpconnect/loader/mozJSComponentLoader.h | 3 + js/xpconnect/src/XPCShellImpl.cpp | 1 + testing/xpcshell/head.js | 4 +- 31 files changed, 507 insertions(+), 85 deletions(-) diff --git a/js/public/MemoryMetrics.h b/js/public/MemoryMetrics.h index 309691cd74ac..7fae00000a0a 100644 --- a/js/public/MemoryMetrics.h +++ b/js/public/MemoryMetrics.h @@ -696,7 +696,8 @@ struct CompartmentStats macro(Other, MallocHeap, objectMetadataTable) \ macro(Other, MallocHeap, crossCompartmentWrappersTable) \ macro(Other, MallocHeap, regexpCompartment) \ - macro(Other, MallocHeap, savedStacksSet) + macro(Other, MallocHeap, savedStacksSet) \ + macro(Other, MallocHeap, nonSyntacticLexicalScopesTable) CompartmentStats() : FOR_EACH_SIZE(ZERO_SIZE) diff --git a/js/src/builtin/Eval.cpp b/js/src/builtin/Eval.cpp index 85fb4bdd6c3b..6129cd127b5b 100644 --- a/js/src/builtin/Eval.cpp +++ b/js/src/builtin/Eval.cpp @@ -495,8 +495,10 @@ js::ExecuteInGlobalAndReturnScope(JSContext* cx, HandleObject global, HandleScri MOZ_RELEASE_ASSERT(scriptArg->hasNonSyntacticScope()); RootedScript script(cx, scriptArg); + Rooted globalRoot(cx, &global->as()); if (script->compartment() != cx->compartment()) { - Rooted staticScope(cx, StaticNonSyntacticScopeObjects::create(cx, nullptr)); + Rooted staticScope(cx, &globalRoot->lexicalScope().staticBlock()); + staticScope = StaticNonSyntacticScopeObjects::create(cx, staticScope); if (!staticScope) return false; script = CloneGlobalScript(cx, staticScope, script); @@ -506,8 +508,15 @@ js::ExecuteInGlobalAndReturnScope(JSContext* cx, HandleObject global, HandleScri Debugger::onNewScript(cx, script); } - Rooted globalRoot(cx, &global->as()); - Rooted scope(cx, NonSyntacticVariablesObject::create(cx, globalRoot)); + Rooted globalLexical(cx, &globalRoot->lexicalScope()); + Rooted scope(cx, NonSyntacticVariablesObject::create(cx, globalLexical)); + if (!scope) + return false; + + // Unlike the non-syntactic scope chain API used by the subscript loader, + // this API creates a fresh block scope each time. + RootedObject enclosingStaticScope(cx, script->enclosingStaticScope()); + scope = ClonedBlockObject::createNonSyntactic(cx, enclosingStaticScope, scope); if (!scope) return false; diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index edf6e318309f..665d9970f6b0 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -2344,7 +2344,8 @@ EvalReturningScope(JSContext* cx, unsigned argc, Value* vp) global = JS::CurrentGlobalOrNull(cx); } - RootedObject scope(cx); + RootedObject varObj(cx); + RootedObject lexicalScope(cx); { // If we're switching globals here, ExecuteInGlobalAndReturnScope will @@ -2352,14 +2353,29 @@ EvalReturningScope(JSContext* cx, unsigned argc, Value* vp) // executing it. AutoCompartment ac(cx, global); - if (!js::ExecuteInGlobalAndReturnScope(cx, global, script, &scope)) + if (!js::ExecuteInGlobalAndReturnScope(cx, global, script, &lexicalScope)) return false; + + varObj = lexicalScope->enclosingScope(); } - if (!cx->compartment()->wrap(cx, &scope)) + RootedObject rv(cx, JS_NewPlainObject(cx)); + if (!rv) return false; - args.rval().setObject(*scope); + RootedValue varObjVal(cx, ObjectValue(*varObj)); + if (!cx->compartment()->wrap(cx, &varObjVal)) + return false; + if (!JS_SetProperty(cx, rv, "vars", varObjVal)) + return false; + + RootedValue lexicalScopeVal(cx, ObjectValue(*lexicalScope)); + if (!cx->compartment()->wrap(cx, &lexicalScopeVal)) + return false; + if (!JS_SetProperty(cx, rv, "lexicals", lexicalScopeVal)) + return false; + + args.rval().setObject(*rv); return true; } diff --git a/js/src/jit-test/tests/debug/onNewScript-ExecuteInGlobalAndReturnScope.js b/js/src/jit-test/tests/debug/onNewScript-ExecuteInGlobalAndReturnScope.js index a0dca8a3fe37..7fb6ebf3a35a 100644 --- a/js/src/jit-test/tests/debug/onNewScript-ExecuteInGlobalAndReturnScope.js +++ b/js/src/jit-test/tests/debug/onNewScript-ExecuteInGlobalAndReturnScope.js @@ -25,8 +25,8 @@ dbg.onDebuggerStatement = function (frame) { }; assertEq(log, ''); -var evalScope = g.evalReturningScope("canary = 'dead'; debugger; // nee", g2); +var evalScopes = g.evalReturningScope("canary = 'dead'; let lex = 42; debugger; // nee", g2); assertEq(log, 'ecbd'); assertEq(canary, 42); -assertEq(evalScope.canary, 'dead'); - +assertEq(evalScopes.vars.canary, 'dead'); +assertEq(evalScopes.lexicals.lex, 42); diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index c4daec484a12..166e6c978394 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -2481,8 +2481,8 @@ BaselineCompiler::emit_JSOP_DEFVAR() return callVM(DefVarInfo); } -typedef bool (*DefLexicalFn)(JSContext*, HandlePropertyName, unsigned); -static const VMFunction DefLexicalInfo = FunctionInfo(DefLexicalOperation); +typedef bool (*DefLexicalFn)(JSContext*, HandlePropertyName, unsigned, HandleObject); +static const VMFunction DefLexicalInfo = FunctionInfo(DefLexical); bool BaselineCompiler::emit_JSOP_DEFCONST() @@ -2500,8 +2500,11 @@ BaselineCompiler::emit_JSOP_DEFLET() attrs |= JSPROP_READONLY; MOZ_ASSERT(attrs <= UINT32_MAX); + masm.loadPtr(frame.addressOfScopeChain(), R0.scratchReg()); + prepareVMCall(); + pushArg(R0.scratchReg()); pushArg(Imm32(attrs)); pushArg(ImmGCPtr(script->getName(pc))); diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index fa20f1f7b5e7..cac90c6e9de9 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -7617,7 +7617,12 @@ DoSetPropFallback(JSContext* cx, BaselineFrame* frame, ICSetProp_Fallback* stub_ obj->as().setAliasedVar(cx, ScopeCoordinate(pc), name, rhs); } else if (op == JSOP_INITGLEXICAL) { RootedValue v(cx, rhs); - InitGlobalLexicalOperation(cx, script, pc, v); + ClonedBlockObject* lexicalScope; + if (script->hasNonSyntacticScope()) + lexicalScope = &NearestEnclosingExtensibleLexicalScope(frame->scopeChain()); + else + lexicalScope = &cx->global()->lexicalScope(); + InitGlobalLexicalOperation(cx, lexicalScope, script, pc, v); } else { MOZ_ASSERT(op == JSOP_SETPROP || op == JSOP_STRICTSETPROP); diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 6cf16cff7add..0795880d7b82 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -3729,7 +3729,7 @@ CodeGenerator::visitDefVar(LDefVar* lir) } typedef bool (*DefLexicalFn)(JSContext*, HandlePropertyName, unsigned); -static const VMFunction DefLexicalInfo = FunctionInfo(DefLexicalOperation); +static const VMFunction DefLexicalInfo = FunctionInfo(DefGlobalLexical); void CodeGenerator::visitDefLexical(LDefLexical* lir) diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index c518e7b6062e..4b18fc0b94ad 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -1768,6 +1768,7 @@ IonBuilder::inspectOpcode(JSOp op) return true; case JSOP_INITGLEXICAL: { + MOZ_ASSERT(!script()->hasNonSyntacticScope()); MDefinition* value = current->pop(); current->push(constant(ObjectValue(script()->global().lexicalScope()))); current->push(value); @@ -12661,6 +12662,7 @@ IonBuilder::jsop_defvar(uint32_t index) bool IonBuilder::jsop_deflexical(uint32_t index) { + MOZ_ASSERT(!script()->hasNonSyntacticScope()); MOZ_ASSERT(JSOp(*pc) == JSOP_DEFLET || JSOp(*pc) == JSOP_DEFCONST); PropertyName* name = script()->getName(index); diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index 84dc42ea6c1e..5a664eda7456 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -3341,7 +3341,8 @@ SetPropertyIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex RootedScript script(cx); jsbytecode* pc; cache.getScriptedLocation(&script, &pc); - InitGlobalLexicalOperation(cx, script, pc, value); + MOZ_ASSERT(!script->hasNonSyntacticScope()); + InitGlobalLexicalOperation(cx, &cx->global()->lexicalScope(), script, pc, value); } else { if (!SetProperty(cx, obj, name, value, cache.strict(), cache.pc())) return false; diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 6f6185b2c510..8b05380bb4d5 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -177,6 +177,27 @@ DefVar(JSContext* cx, HandlePropertyName dn, unsigned attrs, HandleObject scopeC return DefVarOperation(cx, obj, dn, attrs); } +bool +DefLexical(JSContext* cx, HandlePropertyName dn, unsigned attrs, HandleObject scopeChain) +{ + // Find the extensible lexical scope. + Rooted lexical(cx, &NearestEnclosingExtensibleLexicalScope(scopeChain)); + + // Find the variables object. + RootedObject varObj(cx, scopeChain); + while (!varObj->isQualifiedVarObj()) + varObj = varObj->enclosingScope(); + + return DefLexicalOperation(cx, lexical, varObj, dn, attrs); +} + +bool +DefGlobalLexical(JSContext* cx, HandlePropertyName dn, unsigned attrs) +{ + Rooted globalLexical(cx, &cx->global()->lexicalScope()); + return DefLexicalOperation(cx, globalLexical, cx->global(), dn, attrs); +} + bool MutatePrototype(JSContext* cx, HandlePlainObject obj, HandleValue value) { diff --git a/js/src/jit/VMFunctions.h b/js/src/jit/VMFunctions.h index 14373f243e9e..1af58e0ad82e 100644 --- a/js/src/jit/VMFunctions.h +++ b/js/src/jit/VMFunctions.h @@ -589,6 +589,8 @@ bool CheckOverRecursedWithExtra(JSContext* cx, BaselineFrame* frame, uint32_t extra, uint32_t earlyCheck); bool DefVar(JSContext* cx, HandlePropertyName dn, unsigned attrs, HandleObject scopeChain); +bool DefLexical(JSContext* cx, HandlePropertyName dn, unsigned attrs, HandleObject scopeChain); +bool DefGlobalLexical(JSContext* cx, HandlePropertyName dn, unsigned attrs); bool MutatePrototype(JSContext* cx, HandlePlainObject obj, HandleValue value); bool InitProp(JSContext* cx, HandleObject obj, HandlePropertyName name, HandleValue value, jsbytecode* pc); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 1e4e5861b44f..0e7968271744 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -1458,6 +1458,30 @@ JS_IsGlobalObject(JSObject* obj) return obj->is(); } +extern JS_PUBLIC_API(JSObject*) +JS_GlobalLexicalScope(JSObject* obj) +{ + return &obj->as().lexicalScope(); +} + +extern JS_PUBLIC_API(bool) +JS_HasExtensibleLexicalScope(JSObject* obj) +{ + return obj->is() || obj->compartment()->getNonSyntacticLexicalScope(obj); +} + +extern JS_PUBLIC_API(JSObject*) +JS_ExtensibleLexicalScope(JSObject* obj) +{ + JSObject* lexical = nullptr; + if (obj->is()) + lexical = JS_GlobalLexicalScope(obj); + else + lexical = obj->compartment()->getNonSyntacticLexicalScope(obj); + MOZ_ASSERT(lexical); + return lexical; +} + JS_PUBLIC_API(JSObject*) JS_GetGlobalForCompartmentOrNull(JSContext* cx, JSCompartment* c) { @@ -3456,6 +3480,19 @@ CreateNonSyntacticScopeChain(JSContext* cx, AutoObjectVector& scopeChain, // See JSObject::isQualifiedVarObj. if (!dynamicScopeObj->setQualifiedVarObj(cx)) return false; + + // Also get a non-syntactic lexical scope to capture 'let' and 'const' + // bindings. To persist lexical bindings, we have a 1-1 mapping with + // the final unwrapped dynamic scope object (the scope that stores the + // 'var' bindings) and the lexical scope. + // + // TODOshu: disallow the subscript loader from using non-distinguished + // objects as dynamic scopes. + dynamicScopeObj.set( + cx->compartment()->getOrCreateNonSyntacticLexicalScope(cx, staticScopeObj, + dynamicScopeObj)); + if (!dynamicScopeObj) + return false; } return true; diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 176d6191b892..9e19ca7365e2 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -1572,6 +1572,15 @@ JS_GetGlobalForObject(JSContext* cx, JSObject* obj); extern JS_PUBLIC_API(bool) JS_IsGlobalObject(JSObject* obj); +extern JS_PUBLIC_API(JSObject*) +JS_GlobalLexicalScope(JSObject* obj); + +extern JS_PUBLIC_API(bool) +JS_HasExtensibleLexicalScope(JSObject* obj); + +extern JS_PUBLIC_API(JSObject*) +JS_ExtensibleLexicalScope(JSObject* obj); + /* * May return nullptr, if |c| never had a global (e.g. the atoms compartment), * or if |c|'s global has been collected. diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index cb64f02b3a52..936fec6eedf5 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -66,6 +66,7 @@ JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options = selfHostingScriptSource(nullptr), objectMetadataTable(nullptr), lazyArrayBuffers(nullptr), + nonSyntacticLexicalScopes_(nullptr), gcIncomingGrayPointers(nullptr), gcPreserveJitCode(options.preserveJitCode()), debugModeBits(0), @@ -104,6 +105,7 @@ JSCompartment::~JSCompartment() js_delete(debugScopes); js_delete(objectMetadataTable); js_delete(lazyArrayBuffers); + js_delete(nonSyntacticLexicalScopes_), js_free(enumerators); runtime_->numCompartments--; @@ -494,6 +496,48 @@ JSCompartment::wrap(JSContext* cx, MutableHandle desc) return wrap(cx, desc.value()); } +ClonedBlockObject* +JSCompartment::getOrCreateNonSyntacticLexicalScope(JSContext* cx, + HandleObject enclosingStatic, + HandleObject enclosingScope) +{ + if (!nonSyntacticLexicalScopes_) { + nonSyntacticLexicalScopes_ = cx->new_(cx); + if (!nonSyntacticLexicalScopes_ || !nonSyntacticLexicalScopes_->init()) + return nullptr; + } + + // The key is the unwrapped dynamic scope, as we may be creating different + // DynamicWithObject wrappers each time. + MOZ_ASSERT(!enclosingScope->as().isSyntactic()); + RootedObject key(cx, &enclosingScope->as().object()); + RootedObject lexicalScope(cx, nonSyntacticLexicalScopes_->lookup(key)); + + if (!lexicalScope) { + lexicalScope = ClonedBlockObject::createNonSyntactic(cx, enclosingStatic, enclosingScope); + if (!lexicalScope) + return nullptr; + if (!nonSyntacticLexicalScopes_->add(cx, key, lexicalScope)) + return nullptr; + } + + return &lexicalScope->as(); +} + +ClonedBlockObject* +JSCompartment::getNonSyntacticLexicalScope(JSObject* enclosingScope) const +{ + if (!nonSyntacticLexicalScopes_) + return nullptr; + if (!enclosingScope->is()) + return nullptr; + JSObject* key = &enclosingScope->as().object(); + JSObject* lexicalScope = nonSyntacticLexicalScopes_->lookup(key); + if (!lexicalScope) + return nullptr; + return &lexicalScope->as(); +} + void JSCompartment::traceOutgoingCrossCompartmentWrappers(JSTracer* trc) { @@ -599,6 +643,9 @@ JSCompartment::traceRoots(JSTracer* trc, js::gc::GCRuntime::TraceOrMarkRuntime t MOZ_ASSERT(script == r.front().key(), "const_cast is only a work-around"); } } + + if (nonSyntacticLexicalScopes_) + nonSyntacticLexicalScopes_->trace(trc); } void @@ -1052,7 +1099,8 @@ JSCompartment::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, size_t* objectMetadataTablesArg, size_t* crossCompartmentWrappersArg, size_t* regexpCompartment, - size_t* savedStacksSet) + size_t* savedStacksSet, + size_t* nonSyntacticLexicalScopesArg) { *compartmentObject += mallocSizeOf(this); objectGroups.addSizeOfExcludingThis(mallocSizeOf, tiAllocationSiteTables, @@ -1068,6 +1116,8 @@ JSCompartment::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, *crossCompartmentWrappersArg += crossCompartmentWrappers.sizeOfExcludingThis(mallocSizeOf); *regexpCompartment += regExps.sizeOfExcludingThis(mallocSizeOf); *savedStacksSet += savedStacks_.sizeOfExcludingThis(mallocSizeOf); + if (nonSyntacticLexicalScopes_) + *nonSyntacticLexicalScopesArg += nonSyntacticLexicalScopes_->sizeOfIncludingThis(mallocSizeOf); } void diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index 69ce4af297c7..11b89b48e041 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -29,6 +29,7 @@ template class ComponentFinder; } // namespace gc struct NativeIterator; +class ClonedBlockObject; /* * A single-entry cache for some base-10 double-to-string conversions. This @@ -397,7 +398,8 @@ struct JSCompartment size_t* objectMetadataTables, size_t* crossCompartmentWrappers, size_t* regexpCompartment, - size_t* savedStacksSet); + size_t* savedStacksSet, + size_t* nonSyntacticLexicalScopes); /* * Shared scope property tree, and arena-pool for allocating its nodes. @@ -442,6 +444,13 @@ struct JSCompartment // All unboxed layouts in the compartment. mozilla::LinkedList unboxedLayouts; + private: + // All non-syntactic lexical scopes in the compartment. These are kept in + // a map because when loading scripts into a non-syntactic scope, we need + // to use the same lexical scope to persist lexical bindings. + js::ObjectWeakMap* nonSyntacticLexicalScopes_; + + public: /* During GC, stores the index of this compartment in rt->compartments. */ unsigned gcIndex; @@ -511,6 +520,11 @@ struct JSCompartment explicit WrapperEnum(JSCompartment* c) : js::WrapperMap::Enum(c->crossCompartmentWrappers) {} }; + js::ClonedBlockObject* getOrCreateNonSyntacticLexicalScope(JSContext* cx, + js::HandleObject enclosingStatic, + js::HandleObject enclosingScope); + js::ClonedBlockObject* getNonSyntacticLexicalScope(JSObject* enclosingScope) const; + /* * This method traces data that is live iff we know that this compartment's * global is still live. diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index 2dce032dd6ee..2f5e5127b29c 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -2795,13 +2795,12 @@ SetJitExceptionHandler(JitExceptionHandler handler); #endif /* - * Get the object underlying the object environment (in the ES - * NewObjectEnvironment) sense for a given function. If the function is not - * scripted or does not have an object environment, just returns the function's - * parent. + * Get the nearest enclosing with scope object for a given function. If the + * function is not scripted or is not enclosed by a with scope, returns the + * global. */ extern JS_FRIEND_API(JSObject*) -GetObjectEnvironmentObjectForFunction(JSFunction* fun); +GetNearestEnclosingWithScopeObjectForFunction(JSFunction* fun); /* * Get the first SavedFrame object in this SavedFrame stack whose principals are diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index b631e8c077b6..23a5de92b1ae 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -6525,7 +6525,12 @@ EvaluateInEnv(JSContext* cx, Handle env, HandleValue thisv, AbstractFrameP */ Rooted enclosingStaticScope(cx); if (!IsGlobalLexicalScope(env)) { - enclosingStaticScope = StaticNonSyntacticScopeObjects::create(cx, nullptr); + // If we are doing a global evalWithBindings, we will still need to + // link the static global lexical scope to the static non-syntactic + // scope. + if (IsGlobalLexicalScope(env->enclosingScope())) + enclosingStaticScope = &cx->global()->lexicalScope().staticBlock(); + enclosingStaticScope = StaticNonSyntacticScopeObjects::create(cx, enclosingStaticScope); if (!enclosingStaticScope) return false; } else { @@ -6675,9 +6680,9 @@ DebuggerGenericEval(JSContext* cx, const char* fullMethodName, const Value& code return false; } else { /* - * Use the global as 'this'. If the global is an inner object, it - * should have a thisObject hook that returns the appropriate outer - * object. + * Use the global lexical scope as 'this'. If the global is an inner + * object, it should have a thisObject hook that returns the + * appropriate outer object. */ JSObject* thisObj = GetThisObject(cx, scope); if (!thisObj) diff --git a/js/src/vm/Interpreter-inl.h b/js/src/vm/Interpreter-inl.h index b6ef9630e226..cf370270d365 100644 --- a/js/src/vm/Interpreter-inl.h +++ b/js/src/vm/Interpreter-inl.h @@ -300,19 +300,18 @@ SetNameOperation(JSContext* cx, JSScript* script, jsbytecode* pc, HandleObject s } inline bool -DefLexicalOperation(JSContext* cx, HandlePropertyName name, unsigned attrs) +DefLexicalOperation(JSContext* cx, Handle lexicalScope, + HandleObject varObj, HandlePropertyName name, unsigned attrs) { - Rooted globalLexical(cx, &cx->global()->lexicalScope()); - // Due to the extensibility of the global lexical scope, we must check for // redeclaring a binding. mozilla::Maybe redeclKind; RootedId id(cx, NameToId(name)); RootedShape shape(cx); - if ((shape = globalLexical->lookup(cx, name))) { + if ((shape = lexicalScope->lookup(cx, name))) { redeclKind = mozilla::Some(shape->writable() ? frontend::Definition::LET : frontend::Definition::CONST); - } else if ((shape = cx->global()->lookup(cx, name))) { + } else if (varObj->isNative() && (shape = varObj->as().lookup(cx, name))) { if (!shape->configurable()) redeclKind = mozilla::Some(frontend::Definition::VAR); } else { @@ -332,7 +331,8 @@ DefLexicalOperation(JSContext* cx, HandlePropertyName name, unsigned attrs) } inline bool -DefLexicalOperation(JSContext* cx, JSScript* script, jsbytecode* pc) +DefLexicalOperation(JSContext* cx, ClonedBlockObject* lexicalScopeArg, + JSObject* varObjArg, JSScript* script, jsbytecode* pc) { MOZ_ASSERT(*pc == JSOP_DEFLET || *pc == JSOP_DEFCONST); RootedPropertyName name(cx, script->getName(pc)); @@ -341,17 +341,25 @@ DefLexicalOperation(JSContext* cx, JSScript* script, jsbytecode* pc) if (*pc == JSOP_DEFCONST) attrs |= JSPROP_READONLY; - return DefLexicalOperation(cx, name, attrs); + Rooted lexicalScope(cx, lexicalScopeArg); + RootedObject varObj(cx, varObjArg); + MOZ_ASSERT_IF(!script->hasNonSyntacticScope(), + lexicalScope == &cx->global()->lexicalScope() && varObj == cx->global()); + + return DefLexicalOperation(cx, lexicalScope, varObj, name, attrs); } inline void -InitGlobalLexicalOperation(JSContext* cx, JSScript* script, jsbytecode* pc, HandleValue value) +InitGlobalLexicalOperation(JSContext* cx, ClonedBlockObject* lexicalScopeArg, + JSScript* script, jsbytecode* pc, HandleValue value) { + MOZ_ASSERT_IF(!script->hasNonSyntacticScope(), + lexicalScopeArg == &cx->global()->lexicalScope()); MOZ_ASSERT(*pc == JSOP_INITGLEXICAL); - Rooted globalLexical(cx, &cx->global()->lexicalScope()); - RootedShape shape(cx, globalLexical->lookup(cx, script->getName(pc))); + Rooted lexicalScope(cx, lexicalScopeArg); + RootedShape shape(cx, lexicalScope->lookup(cx, script->getName(pc))); MOZ_ASSERT(shape); - globalLexical->setSlot(shape->slot(), value); + lexicalScope->setSlot(shape->slot(), value); } inline bool diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 4fd40e6fd914..24949a54be42 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -3429,8 +3429,13 @@ END_CASE(JSOP_INITALIASEDLEXICAL) CASE(JSOP_INITGLEXICAL) { + ClonedBlockObject* lexicalScope; + if (script->hasNonSyntacticScope()) + lexicalScope = ®S.fp()->extensibleLexicalScope(); + else + lexicalScope = &cx->global()->lexicalScope(); HandleValue value = REGS.stackHandleAt(-1); - InitGlobalLexicalOperation(cx, script, REGS.pc, value); + InitGlobalLexicalOperation(cx, lexicalScope, script, REGS.pc, value); } END_CASE(JSOP_INITGLEXICAL) @@ -3502,7 +3507,16 @@ END_CASE(JSOP_DEFVAR) CASE(JSOP_DEFCONST) CASE(JSOP_DEFLET) { - if (!DefLexicalOperation(cx, script, REGS.pc)) + ClonedBlockObject* lexicalScope; + JSObject* varObj; + if (script->hasNonSyntacticScope()) { + lexicalScope = ®S.fp()->extensibleLexicalScope(); + varObj = ®S.fp()->varObj(); + } else { + lexicalScope = &cx->global()->lexicalScope(); + varObj = cx->global(); + } + if (!DefLexicalOperation(cx, lexicalScope, varObj, script, REGS.pc)) goto error; } END_CASE(JSOP_DEFLET) diff --git a/js/src/vm/MemoryMetrics.cpp b/js/src/vm/MemoryMetrics.cpp index 3be957eb97c9..1e9c53fa5989 100644 --- a/js/src/vm/MemoryMetrics.cpp +++ b/js/src/vm/MemoryMetrics.cpp @@ -342,7 +342,8 @@ StatsCompartmentCallback(JSRuntime* rt, void* data, JSCompartment* compartment) &cStats.objectMetadataTable, &cStats.crossCompartmentWrappersTable, &cStats.regexpCompartment, - &cStats.savedStacksSet); + &cStats.savedStacksSet, + &cStats.nonSyntacticLexicalScopesTable); } static void diff --git a/js/src/vm/ScopeObject-inl.h b/js/src/vm/ScopeObject-inl.h index d54ef5933a92..84ab6bda7217 100644 --- a/js/src/vm/ScopeObject-inl.h +++ b/js/src/vm/ScopeObject-inl.h @@ -16,6 +16,14 @@ namespace js { +inline ClonedBlockObject& +NearestEnclosingExtensibleLexicalScope(JSObject* scope) +{ + while (!IsExtensibleLexicalScope(scope)) + scope = scope->enclosingScope(); + return scope->as(); +} + inline void ScopeObject::setAliasedVar(JSContext* cx, ScopeCoordinate sc, PropertyName* name, const Value& v) { diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 26ad1c22a423..b7cd20faaab4 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -782,8 +782,10 @@ const Class StaticNonSyntacticScopeObjects::class_ = { }; /* static */ NonSyntacticVariablesObject* -NonSyntacticVariablesObject::create(JSContext* cx, Handle global) +NonSyntacticVariablesObject::create(JSContext* cx, Handle globalLexical) { + MOZ_ASSERT(globalLexical->isGlobal()); + Rooted obj(cx, NewObjectWithNullTaggedProto(cx, TenuredObject, BaseShape::DELEGATE)); @@ -794,7 +796,7 @@ NonSyntacticVariablesObject::create(JSContext* cx, Handle global) if (!obj->setQualifiedVarObj(cx)) return nullptr; - obj->setEnclosingScope(global); + obj->setEnclosingScope(globalLexical); return obj; } @@ -869,6 +871,26 @@ ClonedBlockObject::createGlobal(JSContext* cx, Handle global) return lexical; } +/* static */ ClonedBlockObject* +ClonedBlockObject::createNonSyntactic(JSContext* cx, HandleObject enclosingStatic, + HandleObject enclosingScope) +{ + MOZ_ASSERT(enclosingStatic->is()); + MOZ_ASSERT(!IsSyntacticScope(enclosingScope)); + + Rooted staticLexical(cx, StaticBlockObject::create(cx)); + if (!staticLexical) + return nullptr; + + staticLexical->setLocalOffset(UINT32_MAX); + staticLexical->initEnclosingScope(enclosingStatic); + Rooted lexical(cx, ClonedBlockObject::create(cx, staticLexical, + enclosingScope)); + if (!lexical) + return nullptr; + return lexical; +} + /* static */ ClonedBlockObject* ClonedBlockObject::createHollowForDebug(JSContext* cx, Handle block) { @@ -987,9 +1009,11 @@ static JSObject* block_ThisObject(JSContext* cx, HandleObject obj) { // No other block objects should ever get passed to the 'this' object - // hook. - MOZ_ASSERT(obj->as().isGlobal()); - MOZ_ASSERT(&obj->as().enclosingScope() == cx->global()); + // hook except the global lexical scope and non-syntactic ones. + MOZ_ASSERT(obj->as().isGlobal() || + !obj->as().isSyntactic()); + MOZ_ASSERT_IF(obj->as().isGlobal(), + obj->enclosingScope() == cx->global()); RootedObject enclosing(cx, obj->enclosingScope()); return GetThisObject(cx, enclosing); } @@ -1666,9 +1690,12 @@ class DebugScopeProxy : public BaseProxyHandler if (!shape) return true; - // Currently consider all global lexical bindings to be aliased. - if (IsGlobalLexicalScope(block)) + // Currently consider all global and non-syntactic top-level lexical + // bindings to be aliased. + if (block->isExtensible()) { + MOZ_ASSERT(IsGlobalLexicalScope(block) || !IsSyntacticScope(block)); return true; + } unsigned i = block->staticBlock().shapeToIndex(*shape); if (block->staticBlock().isAliased(i)) @@ -2833,13 +2860,16 @@ js::GetDebugScopeForFrame(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc) // See declaration and documentation in jsfriendapi.h JS_FRIEND_API(JSObject*) -js::GetObjectEnvironmentObjectForFunction(JSFunction* fun) +js::GetNearestEnclosingWithScopeObjectForFunction(JSFunction* fun) { if (!fun->isInterpreted()) return &fun->global(); JSObject* env = fun->environment(); - if (!env || !env->is()) + while (env && !env->is()) + env = env->enclosingScope(); + + if (!env) return &fun->global(); return &env->as().object(); diff --git a/js/src/vm/ScopeObject.h b/js/src/vm/ScopeObject.h index 41661e2e6c85..fe74c60f2077 100644 --- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -215,7 +215,7 @@ ScopeCoordinateFunctionScript(JSScript* script, jsbytecode* pc); * | * ScopeObject---+---+ Engine-internal scope * | | | | | - * | | | | StaticNonSyntacticScopeObjects See NB2 + * | | | | StaticNonSyntacticScopeObjects See "Non-syntactic scope objects" * | | | | * | | | StaticEvalObject Placeholder so eval scopes may be iterated through * | | | @@ -247,9 +247,6 @@ ScopeCoordinateFunctionScript(JSScript* script, jsbytecode* pc); * are cloned at runtime. These objects should never escape into the wild and * support a restricted set of ScopeObject operations. * - * NB2: StaticNonSyntacticScopeObjects notify either of 0+ non-syntactic - * DynamicWithObjects on the dynamic scope chain or a NonSyntacticScopeObject. - * * See also "Debug scope objects" below. */ @@ -459,13 +456,113 @@ class StaticEvalObject : public ScopeObject inline bool isNonGlobal() const; }; -// Static scope objects that stand in for one or more "polluting global" -// scopes on the dynamic scope chain. -// -// There are two flavors of polluting global scopes on the dynamic scope -// chain: either 0+ non-syntactic DynamicWithObjects, or 1 -// NonSyntacticVariablesObject, created exclusively in -// js::ExecuteInGlobalAndReturnScope. +/* + * Non-syntactic scope objects + * + * A non-syntactic scope is one that was not created due to source code. On + * the static scope chain, a single StaticNonSyntacticScopeObjects maps to 0+ + * non-syntactic dynamic scope objects. This is contrasted with syntactic + * scopes, where each syntactic static scope corresponds to 0 or 1 dynamic + * scope objects. + * + * There are 3 kinds of dynamic non-syntactic scopes: + * + * 1. DynamicWithObject + * + * When the embedding compiles or executes a script, it has the option to + * pass in a vector of objects to be used as the initial scope chain. Each + * of those objects is wrapped by a DynamicWithObject. + * + * The innermost scope passed in by the embedding becomes a qualified + * variables object that captures 'var' bindings. That is, it wraps the + * holder object of 'var' bindings. + * + * Does not hold 'let' or 'const' bindings. + * + * 2. NonSyntacticVariablesObject + * + * When the embedding wants qualified 'var' bindings and unqualified + * bareword assignments to go on a different object than the global + * object. While any object can be made into a qualified variables object, + * only the GlobalObject and NonSyntacticVariablesObject are considered + * unqualified variables objects. + * + * Unlike DynamicWithObjects, this object is itself the holder of 'var' + * bindings. + * + * Does not hold 'let' or 'const' bindings. + * + * 3. ClonedBlockObject + * + * Each non-syntactic object used as a qualified variables object needs to + * enclose a non-syntactic ClonedBlockObject to hold 'let' and 'const' + * bindings. There is a bijection per compartment between the non-syntactic + * variables objects and their non-syntactic ClonedBlockObjects. + * + * Does not hold 'var' bindings. + * + * The embedding (Gecko) uses non-syntactic scopes for various things, some of + * which are detailed below. All scope chain listings below are, from top to + * bottom, outermost to innermost. + * + * A. Component loading + * + * Components may be loaded in "reuse loader global" mode, where to save on + * memory, all JSMs and JS-implemented XPCOM modules are loaded into a single + * global. Each individual JSMs are compiled as functions with their own + * FakeBackstagePass. They have the following dynamic scope chain: + * + * BackstagePass global + * | + * Global lexical scope + * | + * DynamicWithObject wrapping FakeBackstagePass + * | + * Non-syntactic lexical scope + * + * B. Subscript loading + * + * Subscripts may be loaded into a target object. They have the following + * dynamic scope chain: + * + * Loader global + * | + * Global lexical scope + * | + * DynamicWithObject wrapping target + * | + * ClonedBlockObject + * + * C. Frame scripts + * + * XUL frame scripts are always loaded with a NonSyntacticVariablesObject as a + * "polluting global". This is done exclusively in + * js::ExecuteInGlobalAndReturnScope. + * + * Loader global + * | + * Global lexical scope + * | + * NonSyntacticVariablesObject + * | + * ClonedBlockObject + * + * D. XBL + * + * XBL methods are compiled as functions with XUL elements on the scope chain. + * For a chain of elements e0,...,eN: + * + * ... + * | + * DynamicWithObject wrapping eN + * | + * ... + * | + * DynamicWithObject wrapping e0 + * | + * ClonedBlockObject + * + */ class StaticNonSyntacticScopeObjects : public ScopeObject { public: @@ -482,7 +579,7 @@ class StaticNonSyntacticScopeObjects : public ScopeObject // A non-syntactic dynamic scope object that captures non-lexical // bindings. That is, a scope object that captures both qualified var // assignments and unqualified bareword assignments. Its parent is always the -// real global. +// global lexical scope. // // This is used in ExecuteInGlobalAndReturnScope and sits in front of the // global scope to capture 'var' and bareword asignments. @@ -492,7 +589,8 @@ class NonSyntacticVariablesObject : public ScopeObject static const unsigned RESERVED_SLOTS = 1; static const Class class_; - static NonSyntacticVariablesObject* create(JSContext* cx, Handle global); + static NonSyntacticVariablesObject* create(JSContext* cx, + Handle globalLexical); }; class NestedScopeObject : public ScopeObject @@ -703,10 +801,14 @@ class StaticBlockObject : public BlockObject } // Is this the static global lexical scope? - bool isGlobal() { + bool isGlobal() const { return !enclosingStaticScope(); } + bool isSyntactic() const { + return !isExtensible() || isGlobal(); + } + /* Frontend-only functions ***********************************************/ /* Initialization functions for above fields. */ @@ -765,6 +867,9 @@ class ClonedBlockObject : public BlockObject static ClonedBlockObject* createGlobal(JSContext* cx, Handle global); + static ClonedBlockObject* createNonSyntactic(JSContext* cx, HandleObject enclosingStatic, + HandleObject enclosingScope); + static ClonedBlockObject* createHollowForDebug(JSContext* cx, Handle block); @@ -795,6 +900,10 @@ class ClonedBlockObject : public BlockObject return enclosingScope().as(); } + bool isSyntactic() const { + return !isExtensible() || isGlobal(); + } + /* Copy in all the unaliased formals and locals. */ void copyUnaliasedValues(AbstractFramePtr frame); @@ -1179,9 +1288,25 @@ namespace js { inline bool IsSyntacticScope(JSObject* scope) { - return scope->is() && - (!scope->is() || scope->as().isSyntactic()) && - !scope->is(); + if (!scope->is()) + return false; + + if (scope->is()) + return scope->as().isSyntactic(); + + if (scope->is()) + return scope->as().isSyntactic(); + + if (scope->is()) + return false; + + return true; +} + +inline bool +IsExtensibleLexicalScope(JSObject* scope) +{ + return scope->is() && scope->as().isExtensible(); } inline bool @@ -1234,13 +1359,12 @@ inline bool ScopeIter::hasNonSyntacticScopeObject() const { // The case we're worrying about here is a NonSyntactic static scope which - // has 0+ corresponding non-syntactic DynamicWithObject scopes or a - // NonSyntacticVariablesObject. + // has 0+ corresponding non-syntactic DynamicWithObject scopes, a + // NonSyntacticVariablesObject, or a non-syntactic ClonedBlockObject. if (ssi_.type() == StaticScopeIter::NonSyntactic) { MOZ_ASSERT_IF(scope_->is(), !scope_->as().isSyntactic()); - return scope_->is() || - scope_->is(); + return scope_->is() && !IsSyntacticScope(scope_); } return false; } diff --git a/js/src/vm/Stack-inl.h b/js/src/vm/Stack-inl.h index 1d43084d713b..9dd615808168 100644 --- a/js/src/vm/Stack-inl.h +++ b/js/src/vm/Stack-inl.h @@ -62,7 +62,7 @@ InterpreterFrame::global() const } inline JSObject& -InterpreterFrame::varObj() +InterpreterFrame::varObj() const { JSObject* obj = scopeChain(); while (!obj->isQualifiedVarObj()) @@ -70,6 +70,12 @@ InterpreterFrame::varObj() return *obj; } +inline ClonedBlockObject& +InterpreterFrame::extensibleLexicalScope() const +{ + return NearestEnclosingExtensibleLexicalScope(scopeChain()); +} + inline JSCompartment* InterpreterFrame::compartment() const { diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 8c5c98950262..08a8809522f8 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -144,7 +144,11 @@ AssertDynamicScopeMatchesStaticScope(JSContext* cx, JSScript* script, JSObject* RootedObject enclosingScope(cx, script->enclosingStaticScope()); for (StaticScopeIter i(enclosingScope); !i.done(); i++) { if (i.type() == StaticScopeIter::NonSyntactic) { - while (scope->is() || scope->is()) { + while (scope->is() || + scope->is() || + (scope->is() && + !scope->as().isSyntactic())) + { MOZ_ASSERT(!IsSyntacticScope(scope)); scope = &scope->as().enclosingScope(); } diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index 92f619f81f40..731c0bb0dfa9 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -45,6 +45,7 @@ class ScriptFrameIter; class SPSProfiler; class InterpreterFrame; class StaticBlockObject; +class ClonedBlockObject; class ScopeCoordinate; @@ -616,7 +617,8 @@ class InterpreterFrame inline ScopeObject& aliasedVarScope(ScopeCoordinate sc) const; inline GlobalObject& global() const; inline CallObject& callObj() const; - inline JSObject& varObj(); + inline JSObject& varObj() const; + inline ClonedBlockObject& extensibleLexicalScope() const; inline void pushOnScopeChain(ScopeObject& scope); inline void popOffScopeChain(); diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index 1abb36a0b892..0fc408bd5748 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -2566,9 +2566,11 @@ UpdatePropertyType(ExclusiveContext* cx, HeapTypeSet* types, NativeObject* obj, * comment). * * Also don't add untracked values (initial uninitialized lexical - * magic values and optimized out values) as appearing in CallObjects. + * magic values and optimized out values) as appearing in CallObjects + * and the global lexical scope. */ - MOZ_ASSERT_IF(TypeSet::IsUntrackedValue(value), obj->is()); + MOZ_ASSERT_IF(TypeSet::IsUntrackedValue(value), + obj->is() || IsExtensibleLexicalScope(obj)); if ((indexed || !value.isUndefined() || !CanHaveEmptyPropertyTypesForOwnProperty(obj)) && !TypeSet::IsUntrackedValue(value)) { diff --git a/js/xpconnect/loader/mozJSComponentLoader.cpp b/js/xpconnect/loader/mozJSComponentLoader.cpp index 367b9336f0eb..7ef691f168b3 100644 --- a/js/xpconnect/loader/mozJSComponentLoader.cpp +++ b/js/xpconnect/loader/mozJSComponentLoader.cpp @@ -325,6 +325,25 @@ mozJSComponentLoader::ReallyInit() return NS_OK; } +// For terrible compatibility reasons, we need to consider both the global +// lexical scope and the global of modules when searching for exported +// symbols. +static JSObject* +ResolveModuleObjectProperty(JSContext* aCx, HandleObject aModObj, const char* name) +{ + if (JS_HasExtensibleLexicalScope(aModObj)) { + RootedObject lexical(aCx, JS_ExtensibleLexicalScope(aModObj)); + bool found; + if (!JS_HasOwnProperty(aCx, lexical, name, &found)) { + return nullptr; + } + if (found) { + return lexical; + } + } + return aModObj; +} + const mozilla::Module* mozJSComponentLoader::LoadModule(FileLocation& aFile) { @@ -372,9 +391,12 @@ mozJSComponentLoader::LoadModule(FileLocation& aFile) JSAutoCompartment ac(cx, entry->obj); RootedObject entryObj(cx, entry->obj); + RootedObject NSGetFactoryHolder(cx, ResolveModuleObjectProperty(cx, entryObj, "NSGetFactory")); RootedValue NSGetFactory_val(cx); - if (!JS_GetProperty(cx, entryObj, "NSGetFactory", &NSGetFactory_val) || - NSGetFactory_val.isUndefined()) { + if (!NSGetFactoryHolder || + !JS_GetProperty(cx, NSGetFactoryHolder, "NSGetFactory", &NSGetFactory_val) || + NSGetFactory_val.isUndefined()) + { return nullptr; } @@ -424,7 +446,7 @@ mozJSComponentLoader::FindTargetObject(JSContext* aCx, if (mReuseLoaderGlobal) { JSFunction* fun = js::GetOutermostEnclosingFunctionOfScriptedCaller(aCx); if (fun) { - JSObject* funParent = js::GetObjectEnvironmentObjectForFunction(fun); + JSObject* funParent = js::GetNearestEnclosingWithScopeObjectForFunction(fun); if (JS_GetClass(funParent) == &kFakeBackstagePassJSClass) targetObject = funParent; } @@ -964,6 +986,9 @@ mozJSComponentLoader::UnloadModules() RootedObject global(cx, mLoaderGlobal->GetJSObject()); if (global) { JSAutoCompartment ac(cx, global); + if (JS_HasExtensibleLexicalScope(global)) { + JS_SetAllNonReservedSlotsToUndefined(cx, JS_ExtensibleLexicalScope(global)); + } JS_SetAllNonReservedSlotsToUndefined(cx, global); } else { NS_WARNING("Going to leak!"); @@ -1074,6 +1099,22 @@ mozJSComponentLoader::IsModuleLoaded(const nsACString& aLocation, return NS_OK; } +static JSObject* +ResolveModuleObjectPropertyById(JSContext* aCx, HandleObject aModObj, HandleId id) +{ + if (JS_HasExtensibleLexicalScope(aModObj)) { + RootedObject lexical(aCx, JS_ExtensibleLexicalScope(aModObj)); + bool found; + if (!JS_HasOwnPropertyById(aCx, lexical, id, &found)) { + return nullptr; + } + if (found) { + return lexical; + } + } + return aModObj; +} + nsresult mozJSComponentLoader::ImportInto(const nsACString& aLocation, HandleObject targetObj, @@ -1178,8 +1219,10 @@ mozJSComponentLoader::ImportInto(const nsACString& aLocation, JSAutoCompartment ac(cx, mod->obj); RootedValue symbols(cx); - RootedObject modObj(cx, mod->obj); - if (!JS_GetProperty(cx, modObj, + RootedObject exportedSymbolsHolder(cx, ResolveModuleObjectProperty(cx, mod->obj, + "EXPORTED_SYMBOLS")); + if (!exportedSymbolsHolder || + !JS_GetProperty(cx, exportedSymbolsHolder, "EXPORTED_SYMBOLS", &symbols)) { return ReportOnCaller(cxhelper, ERROR_NOT_PRESENT, PromiseFlatCString(aLocation).get()); @@ -1210,6 +1253,7 @@ mozJSComponentLoader::ImportInto(const nsACString& aLocation, RootedValue value(cx); RootedId symbolId(cx); + RootedObject symbolHolder(cx); for (uint32_t i = 0; i < symbolCount; ++i) { if (!JS_GetElement(cx, symbolsObj, i, &value) || !value.isString() || @@ -1218,8 +1262,9 @@ mozJSComponentLoader::ImportInto(const nsACString& aLocation, PromiseFlatCString(aLocation).get(), i); } - RootedObject modObj(cx, mod->obj); - if (!JS_GetPropertyById(cx, modObj, symbolId, &value)) { + symbolHolder = ResolveModuleObjectPropertyById(cx, mod->obj, symbolId); + if (!symbolHolder || + !JS_GetPropertyById(cx, symbolHolder, symbolId, &value)) { JSAutoByteString bytes(cx, JSID_TO_STRING(symbolId)); if (!bytes) return NS_ERROR_FAILURE; diff --git a/js/xpconnect/loader/mozJSComponentLoader.h b/js/xpconnect/loader/mozJSComponentLoader.h index e55b0f77052c..e81321eadf12 100644 --- a/js/xpconnect/loader/mozJSComponentLoader.h +++ b/js/xpconnect/loader/mozJSComponentLoader.h @@ -112,6 +112,9 @@ class mozJSComponentLoader : public mozilla::ModuleLoader, mozilla::AutoJSContext cx; JSAutoCompartment ac(cx, obj); + if (JS_HasExtensibleLexicalScope(obj)) { + JS_SetAllNonReservedSlotsToUndefined(cx, JS_ExtensibleLexicalScope(obj)); + } JS_SetAllNonReservedSlotsToUndefined(cx, obj); obj = nullptr; thisObjectKey = nullptr; diff --git a/js/xpconnect/src/XPCShellImpl.cpp b/js/xpconnect/src/XPCShellImpl.cpp index 31416aa2f0bd..c518debefd44 100644 --- a/js/xpconnect/src/XPCShellImpl.cpp +++ b/js/xpconnect/src/XPCShellImpl.cpp @@ -1556,6 +1556,7 @@ XRE_XPCShellMain(int argc, char** argv, char** envp) JS_DropPrincipals(rt, gJSPrincipals); JS_SetAllNonReservedSlotsToUndefined(cx, glob); + JS_SetAllNonReservedSlotsToUndefined(cx, JS_GlobalLexicalScope(glob)); JS_GC(rt); } JS_GC(rt); diff --git a/testing/xpcshell/head.js b/testing/xpcshell/head.js index 3bde8b0853f8..b2143155d184 100644 --- a/testing/xpcshell/head.js +++ b/testing/xpcshell/head.js @@ -333,7 +333,7 @@ function _register_protocol_handlers() { } function _register_modules_protocol_handler() { - if (!this._TESTING_MODULES_DIR) { + if (!_TESTING_MODULES_DIR) { throw new Error("Please define a path where the testing modules can be " + "found in a variable called '_TESTING_MODULES_DIR' before " + "head.js is included."); @@ -1227,7 +1227,7 @@ function do_load_child_test_harness() + "const _JSDEBUGGER_PORT=0; " + "const _XPCSHELL_PROCESS='child';"; - if (this._TESTING_MODULES_DIR) { + if (_TESTING_MODULES_DIR) { command += " const _TESTING_MODULES_DIR=" + uneval(_TESTING_MODULES_DIR) + ";"; } From 99fd14ce85088fa11a3ddddac3a1f9ddde624a30 Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Tue, 6 Oct 2015 14:00:30 -0700 Subject: [PATCH 090/228] Bug 589199 - Fix jit-tests and js reftests. (r=efaust) --- js/src/jit-test/tests/basic/bug673569.js | 8 ++-- js/src/jit-test/tests/basic/bug778268.js | 3 -- .../tests/debug/Debugger-debuggees-19.js | 2 +- .../tests/debug/Environment-getVariable-05.js | 2 +- .../tests/debug/Environment-getVariable-06.js | 2 +- .../tests/debug/Environment-getVariable-11.js | 2 +- .../debug/Environment-getVariable-WouldRun.js | 2 +- .../tests/debug/Environment-inspectable-01.js | 6 ++- .../debug/Environment-optimizedOut-01.js | 2 +- .../tests/debug/Environment-setVariable-01.js | 2 +- .../tests/debug/Environment-setVariable-02.js | 2 +- .../tests/debug/Frame-environment-02.js | 2 +- .../tests/debug/Memory-takeCensus-06.js | 6 +-- .../tests/debug/Memory-takeCensus-10.js | 2 +- js/src/tests/ecma_6/Class/outerBinding.js | 20 +------- ...ith-global-ignores-global-let-variables.js | 1 - js/src/tests/js1_5/extensions/scope-001.js | 7 ++- js/src/tests/js1_7/regress/regress-406477.js | 48 ------------------- .../extensions/clone-complex-object.js | 2 +- .../destructuring-variable-declarations.js | 2 +- .../tests/js1_8_5/reflect-parse/lexicals.js | 2 +- 21 files changed, 32 insertions(+), 93 deletions(-) delete mode 100644 js/src/jit-test/tests/basic/bug778268.js delete mode 100644 js/src/tests/js1_7/regress/regress-406477.js diff --git a/js/src/jit-test/tests/basic/bug673569.js b/js/src/jit-test/tests/basic/bug673569.js index 05f031d9ce3a..acc54277af70 100644 --- a/js/src/jit-test/tests/basic/bug673569.js +++ b/js/src/jit-test/tests/basic/bug673569.js @@ -1,13 +1,13 @@ function qualified_tests(prefix) { - let scope = evalReturningScope(prefix + "var x = 1"); - assertEq(scope.x, 1); + let scopes = evalReturningScope(prefix + "var x = 1"); + assertEq(scopes.vars.x, 1); } qualified_tests(""); qualified_tests("'use strict'; "); -let scope = evalReturningScope("x = 1"); -assertEq(scope.x, 1); +let scopes = evalReturningScope("x = 1"); +assertEq(scopes.vars.x, 1); let fail = true; try { diff --git a/js/src/jit-test/tests/basic/bug778268.js b/js/src/jit-test/tests/basic/bug778268.js deleted file mode 100644 index a48a1ac46aa6..000000000000 --- a/js/src/jit-test/tests/basic/bug778268.js +++ /dev/null @@ -1,3 +0,0 @@ -// Just don't assert -j : 4; -let [j] = [], j; diff --git a/js/src/jit-test/tests/debug/Debugger-debuggees-19.js b/js/src/jit-test/tests/debug/Debugger-debuggees-19.js index 20d9f1599668..5417975aa558 100644 --- a/js/src/jit-test/tests/debug/Debugger-debuggees-19.js +++ b/js/src/jit-test/tests/debug/Debugger-debuggees-19.js @@ -6,7 +6,7 @@ var dbg = new Debugger; var log; dbg.onEnterFrame = function (frame) { log += 'e'; - log += frame.environment.parent.object.label; + log += frame.environment.parent.parent.object.label; }; var g1 = newGlobal(); diff --git a/js/src/jit-test/tests/debug/Environment-getVariable-05.js b/js/src/jit-test/tests/debug/Environment-getVariable-05.js index f4bd52144647..ba1798192024 100644 --- a/js/src/jit-test/tests/debug/Environment-getVariable-05.js +++ b/js/src/jit-test/tests/debug/Environment-getVariable-05.js @@ -4,7 +4,7 @@ var g = newGlobal(); var dbg = Debugger(g); var log = ''; dbg.onDebuggerStatement = function (frame) { - log += frame.environment.parent.getVariable("x") + frame.environment.parent.getVariable("y"); + log += frame.environment.parent.parent.getVariable("x") + frame.environment.parent.parent.getVariable("y"); }; g.eval("var x = 'a'; this.y = 'b'; debugger;"); assertEq(log, 'ab'); diff --git a/js/src/jit-test/tests/debug/Environment-getVariable-06.js b/js/src/jit-test/tests/debug/Environment-getVariable-06.js index 096f77d8e3cd..c147e65df070 100644 --- a/js/src/jit-test/tests/debug/Environment-getVariable-06.js +++ b/js/src/jit-test/tests/debug/Environment-getVariable-06.js @@ -4,7 +4,7 @@ var g = newGlobal(); var dbg = Debugger(g); var log = ''; dbg.onDebuggerStatement = function (frame) { - log += frame.environment.parent.getVariable("x") + frame.environment.parent.getVariable("y"); + log += frame.environment.parent.parent.getVariable("x") + frame.environment.parent.parent.getVariable("y"); }; g.eval("Object.getPrototypeOf(this).x = 'a';\n" + "Object.prototype.y = 'b';\n" + diff --git a/js/src/jit-test/tests/debug/Environment-getVariable-11.js b/js/src/jit-test/tests/debug/Environment-getVariable-11.js index ac144407ebe8..f703f221e731 100644 --- a/js/src/jit-test/tests/debug/Environment-getVariable-11.js +++ b/js/src/jit-test/tests/debug/Environment-getVariable-11.js @@ -5,7 +5,7 @@ var dbg = new Debugger; var gw = dbg.addDebuggee(g); var hits = 0; dbg.onDebuggerStatement = function (frame) { - var a = frame.environment.parent.getVariable('Math'); + var a = frame.environment.parent.parent.getVariable('Math'); assertEq(a instanceof Debugger.Object, true); var b = gw.getOwnPropertyDescriptor('Math').value; assertEq(a, b); diff --git a/js/src/jit-test/tests/debug/Environment-getVariable-WouldRun.js b/js/src/jit-test/tests/debug/Environment-getVariable-WouldRun.js index 8d2457d12fab..495399985c30 100644 --- a/js/src/jit-test/tests/debug/Environment-getVariable-WouldRun.js +++ b/js/src/jit-test/tests/debug/Environment-getVariable-WouldRun.js @@ -8,7 +8,7 @@ var dbg = Debugger(g); var hits = 0; dbg.onDebuggerStatement = function (frame) { assertThrowsInstanceOf(function () { - frame.environment.parent.getVariable("x"); + frame.environment.parent.parent.getVariable("x"); }, Error); hits++; }; diff --git a/js/src/jit-test/tests/debug/Environment-inspectable-01.js b/js/src/jit-test/tests/debug/Environment-inspectable-01.js index ee5897833d51..b639cdc91c54 100644 --- a/js/src/jit-test/tests/debug/Environment-inspectable-01.js +++ b/js/src/jit-test/tests/debug/Environment-inspectable-01.js @@ -46,7 +46,8 @@ function debuggerHandler(frame) { assertEq(ke.getVariable('xk'), 'value of xk'); assertEq(ee.inspectable, true); assertEq(ee.type, 'declarative'); - assertEq(ee.parent.type, 'object'); + assertEq(ee.parent.type, 'declarative'); + assertEq(ee.parent.parent.type, 'object'); dbg.removeDebuggee(g2); @@ -56,7 +57,8 @@ function debuggerHandler(frame) { assertThrowsInstanceOf(() => ke.getVariable('xk'), Error); assertEq(ee.inspectable, true); assertEq(ee.type, 'declarative'); - assertEq(ee.parent.type, 'object'); + assertEq(ee.parent.type, 'declarative'); + assertEq(ee.parent.parent.type, 'object'); dbg.removeDebuggee(g1); diff --git a/js/src/jit-test/tests/debug/Environment-optimizedOut-01.js b/js/src/jit-test/tests/debug/Environment-optimizedOut-01.js index 7701ebc073af..eb3d2ca52eca 100644 --- a/js/src/jit-test/tests/debug/Environment-optimizedOut-01.js +++ b/js/src/jit-test/tests/debug/Environment-optimizedOut-01.js @@ -28,7 +28,7 @@ dbg.onEnterFrame = function (f) { assertEq(funenv.callee, f.older.callee); assertEq(funenv.names().indexOf("x") !== -1, true); - globalenv = funenv.parent.parent; + globalenv = funenv.parent.parent.parent; assertEq(globalenv.optimizedOut, false); assertEq(globalenv.inspectable, true); assertEq(globalenv.type, "object"); diff --git a/js/src/jit-test/tests/debug/Environment-setVariable-01.js b/js/src/jit-test/tests/debug/Environment-setVariable-01.js index 610960241cc3..8e54be56ea31 100644 --- a/js/src/jit-test/tests/debug/Environment-setVariable-01.js +++ b/js/src/jit-test/tests/debug/Environment-setVariable-01.js @@ -3,7 +3,7 @@ var g = newGlobal(); var dbg = Debugger(g); dbg.onDebuggerStatement = function (frame) { - frame.environment.parent.setVariable("x", 2); + frame.environment.parent.parent.setVariable("x", 2); }; g.eval("var x = 1; debugger;"); assertEq(g.x, 2); diff --git a/js/src/jit-test/tests/debug/Environment-setVariable-02.js b/js/src/jit-test/tests/debug/Environment-setVariable-02.js index 02494609e260..2aa8eac6fb06 100644 --- a/js/src/jit-test/tests/debug/Environment-setVariable-02.js +++ b/js/src/jit-test/tests/debug/Environment-setVariable-02.js @@ -4,7 +4,7 @@ var g = newGlobal(); var dbg = new Debugger; var gw = dbg.addDebuggee(g); dbg.onDebuggerStatement = function (frame) { - frame.environment.parent.setVariable("x", gw); + frame.environment.parent.parent.setVariable("x", gw); }; g.eval("var x = 1; debugger;"); assertEq(g.x, g); diff --git a/js/src/jit-test/tests/debug/Frame-environment-02.js b/js/src/jit-test/tests/debug/Frame-environment-02.js index 6d6101c59a47..0ec23842c8da 100644 --- a/js/src/jit-test/tests/debug/Frame-environment-02.js +++ b/js/src/jit-test/tests/debug/Frame-environment-02.js @@ -4,7 +4,7 @@ var g = newGlobal(); var dbg = new Debugger; var gw = dbg.addDebuggee(g); g.h = function () { - var env = dbg.getNewestFrame().environment.parent; + var env = dbg.getNewestFrame().environment.parent.parent; assertEq(env instanceof Debugger.Environment, true); assertEq(env.object, gw); assertEq(env.parent, null); diff --git a/js/src/jit-test/tests/debug/Memory-takeCensus-06.js b/js/src/jit-test/tests/debug/Memory-takeCensus-06.js index 6c70092d717a..542d381746ca 100644 --- a/js/src/jit-test/tests/debug/Memory-takeCensus-06.js +++ b/js/src/jit-test/tests/debug/Memory-takeCensus-06.js @@ -14,15 +14,15 @@ let census = dbg.memory.takeCensus({ breakdown: { by: 'count', count: false, byt assertEq('count' in census, false); assertEq('bytes' in census, false); -let census = dbg.memory.takeCensus({ breakdown: { by: 'count', count: true, bytes: false } }); +census = dbg.memory.takeCensus({ breakdown: { by: 'count', count: true, bytes: false } }); assertEq('count' in census, true); assertEq('bytes' in census, false); -let census = dbg.memory.takeCensus({ breakdown: { by: 'count', count: false, bytes: true } }); +census = dbg.memory.takeCensus({ breakdown: { by: 'count', count: false, bytes: true } }); assertEq('count' in census, false); assertEq('bytes' in census, true); -let census = dbg.memory.takeCensus({ breakdown: { by: 'count', count: true, bytes: true } }); +census = dbg.memory.takeCensus({ breakdown: { by: 'count', count: true, bytes: true } }); assertEq('count' in census, true); assertEq('bytes' in census, true); diff --git a/js/src/jit-test/tests/debug/Memory-takeCensus-10.js b/js/src/jit-test/tests/debug/Memory-takeCensus-10.js index aa811184deb2..e7b82379c485 100644 --- a/js/src/jit-test/tests/debug/Memory-takeCensus-10.js +++ b/js/src/jit-test/tests/debug/Memory-takeCensus-10.js @@ -27,7 +27,7 @@ dbg.memory.trackingAllocationSites = true; g.hold = null; g.fnerd(); -let census = dbg.memory.takeCensus({ +census = dbg.memory.takeCensus({ breakdown: { by: 'objectClass', then: { by: 'allocationStack' } } diff --git a/js/src/tests/ecma_6/Class/outerBinding.js b/js/src/tests/ecma_6/Class/outerBinding.js index 93a5ac9b9d6c..13e7b3951fab 100644 --- a/js/src/tests/ecma_6/Class/outerBinding.js +++ b/js/src/tests/ecma_6/Class/outerBinding.js @@ -25,28 +25,12 @@ assertEq(Foo, 5); assertEq(typeof PermanentBinding, "function"); } -{ - try { - evaluate(\`class x { constructor () { } } - throw new Error("FAIL"); - class y { constructor () { } } - \`); - } catch (e if e instanceof Error) { } - assertEq(typeof x, "function"); - assertEq(y, undefined, "Congrats, you fixed top-level lexical scoping! " + - "Please uncomment the tests below for the real test."); - // assertThrowsInstanceOf(() => y, ReferenceError); -} +evaluate("const globalConstant = 0; var earlyError = true;"); -/* -===== UNCOMMENT ME WHEN ENABLING THE TEST ABOVE. ===== -const globalConstant = 0; -var earlyError = true; try { - ieval("earlyError = false; class globalConstant { constructor() { } }"); + evaluate("earlyError = false; class globalConstant { constructor() { } }"); } catch (e if e instanceof TypeError) { } assertEq(earlyError, true); -*/ function strictEvalShadows() { "use strict"; diff --git a/js/src/tests/ecma_6/LexicalEnvironment/with-global-ignores-global-let-variables.js b/js/src/tests/ecma_6/LexicalEnvironment/with-global-ignores-global-let-variables.js index 7b8230859d45..cce12ef5f5fc 100644 --- a/js/src/tests/ecma_6/LexicalEnvironment/with-global-ignores-global-let-variables.js +++ b/js/src/tests/ecma_6/LexicalEnvironment/with-global-ignores-global-let-variables.js @@ -1,4 +1,3 @@ -// |reftest| fails-if(Function("try{Function('let\x20x=5;');return(evaluate)('let\x20x=3;\\'x\\'\x20in\x20this');}catch(e){return(true);}")()) -- needs bug 589199 fix (top-level let not same as var); please convert AssertEq to assertEq when removing this fails-if, too // Any copyright is dedicated to the Public Domain. // http://creativecommons.org/licenses/publicdomain/ diff --git a/js/src/tests/js1_5/extensions/scope-001.js b/js/src/tests/js1_5/extensions/scope-001.js index c98c1689aeba..b1982126a39e 100644 --- a/js/src/tests/js1_5/extensions/scope-001.js +++ b/js/src/tests/js1_5/extensions/scope-001.js @@ -9,7 +9,12 @@ var status = 'Testing scope after changing obj.__proto__'; var expect= ''; var actual = ''; var obj = {}; -const five = 5; + +Object.defineProperty(this, "five", { + value: 5, + enumerable: true, + writable: false +}); //----------------------------------------------------------------------------- diff --git a/js/src/tests/js1_7/regress/regress-406477.js b/js/src/tests/js1_7/regress/regress-406477.js deleted file mode 100644 index a517be9e3ad2..000000000000 --- a/js/src/tests/js1_7/regress/regress-406477.js +++ /dev/null @@ -1,48 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* 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 BUGNUMBER = 406477; -var summary = 'eval of function x() in a function with an argument "x" and "let x"'; -var actual = ''; -var expect = ''; - - -//----------------------------------------------------------------------------- -test(); -//----------------------------------------------------------------------------- - -function test() -{ - enterFunc ('test'); - printBugNumber(BUGNUMBER); - printStatus (summary); - - function test2(x, src) - { - var y = 1; - { - let x = 2; - let y = 2; - eval(src); - } - return [x, y]; - } - - var expect = actual = ''; - - var [test_param_result, test_var_result] = - test2(1, "function x() { }\nfunction y() { }\n"); - - if (typeof test_param_result != "function") - actual += "Unexpected test_param_result value: "+uneval(test_param_result)+"\n"; - - if (typeof test_var_result != "function") - actual += "Unexpected test_var_result value: "+uneval(test_var_result)+"\n"; - - reportCompare(expect, actual, summary); - - exitFunc ('test'); -} diff --git a/js/src/tests/js1_8_5/extensions/clone-complex-object.js b/js/src/tests/js1_8_5/extensions/clone-complex-object.js index 1cf930bc36df..7a20dbb385a3 100644 --- a/js/src/tests/js1_8_5/extensions/clone-complex-object.js +++ b/js/src/tests/js1_8_5/extensions/clone-complex-object.js @@ -242,7 +242,7 @@ let obj = { 'foo': foo, 'baz': baz }; check(obj); -for (var obj of new getTestContent) +for (obj of new getTestContent) check(obj); // Stolen wholesale from postMessage_structured_clone_helper.js diff --git a/js/src/tests/js1_8_5/reflect-parse/destructuring-variable-declarations.js b/js/src/tests/js1_8_5/reflect-parse/destructuring-variable-declarations.js index 1c8afb71ac20..01f896d5784b 100644 --- a/js/src/tests/js1_8_5/reflect-parse/destructuring-variable-declarations.js +++ b/js/src/tests/js1_8_5/reflect-parse/destructuring-variable-declarations.js @@ -13,7 +13,7 @@ function testVarPatternCombinations(makePattSrc, makePattPatt) { // variable declarations in blocks assertDecl("var " + pattSrcs[i].join(",") + ";", varDecl(pattPatts[i])); - assertGlobalDecl("let " + pattSrcs[i].join(",") + ";", varDecl(pattPatts[i])); + assertGlobalDecl("let " + pattSrcs[i].join(",") + ";", letDecl(pattPatts[i])); assertLocalDecl("let " + pattSrcs[i].join(",") + ";", letDecl(pattPatts[i])); assertBlockDecl("let " + pattSrcs[i].join(",") + ";", letDecl(pattPatts[i])); diff --git a/js/src/tests/js1_8_5/reflect-parse/lexicals.js b/js/src/tests/js1_8_5/reflect-parse/lexicals.js index 1b29c78d6fff..500e5bece14c 100644 --- a/js/src/tests/js1_8_5/reflect-parse/lexicals.js +++ b/js/src/tests/js1_8_5/reflect-parse/lexicals.js @@ -2,7 +2,7 @@ function test() { // global let is var -assertGlobalDecl("let {x:y} = foo;", varDecl([{ id: objPatt([assignProp("x", ident("y"))]), +assertGlobalDecl("let {x:y} = foo;", letDecl([{ id: objPatt([assignProp("x", ident("y"))]), init: ident("foo") }])); // function-global let is let assertLocalDecl("let {x:y} = foo;", letDecl([{ id: objPatt([assignProp("x", ident("y"))]), From 52e365bb7b009e8a946d1c1338f1afabb58faa06 Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Tue, 6 Oct 2015 14:00:30 -0700 Subject: [PATCH 091/228] Bug 1202902 - Fix the world. (r=ato for marionette, rs=Mossop for rest) --- accessible/tests/mochitest/relations.js | 40 +++++------ .../source/test/fixtures/addon/bootstrap.js | 2 +- addon-sdk/source/test/test-content-script.js | 2 +- browser/base/content/browser.js | 2 + .../test/general/healthreport_pingData.js | 2 +- browser/base/content/urlbarBindings.xml | 18 +++-- .../customizableui/content/panelUI.js | 2 + ...browser_1096763_seen_widgets_post_reset.js | 7 +- .../components/downloads/content/downloads.js | 14 +++- .../components/downloads/content/indicator.js | 5 ++ .../loop/modules/LoopRoomsCache.jsm | 1 + .../loop/modules/MozLoopService.jsm | 8 +++ .../sessionstore/test/browser_privatetabs.js | 4 -- browser/experiments/Experiments.jsm | 1 + browser/modules/Windows8WindowFrameColor.jsm | 2 +- .../client/canvasdebugger/canvasdebugger.js | 1 + .../client/debugger/debugger-controller.js | 3 + devtools/client/debugger/debugger-view.js | 13 ++++ .../browser_dbg_break-on-next-console.js | 6 +- .../mochitest/browser_dbg_break-on-next.js | 20 ++++-- .../browser_dbg_pause-exceptions-01.js | 12 ++-- .../browser_dbg_pause-exceptions-02.js | 8 +-- .../browser_dbg_variables-view-06.js | 2 +- .../browser_dbg_variables-view-filter-01.js | 24 +++++-- .../browser_dbg_variables-view-filter-02.js | 20 +++++- .../browser_dbg_variables-view-filter-03.js | 20 +++++- .../browser_dbg_variables-view-filter-04.js | 69 +++++++++++-------- .../browser_dbg_variables-view-filter-05.js | 44 ++++++++---- ..._dbg_variables-view-frame-parameters-01.js | 14 +++- ..._dbg_variables-view-frame-parameters-03.js | 8 +-- .../browser_dbg_variables-view-override-01.js | 11 ++- .../browser_dbg_variables-view-popup-16.js | 2 +- .../browser_dbg_variables-view-reexpand-01.js | 17 ++++- .../browser_dbg_variables-view-reexpand-02.js | 17 ++++- .../browser_dbg_variables-view-webidl.js | 4 +- .../test/mochitest/doc_function-search.html | 6 +- devtools/client/debugger/utils.js | 4 +- devtools/client/inspector/inspector-panel.js | 4 +- .../markupview/test/actor_events_form.js | 4 +- .../netmonitor/netmonitor-controller.js | 4 ++ .../performance/performance-controller.js | 5 ++ devtools/client/performance/test/head.js | 5 +- devtools/client/performance/views/overview.js | 2 +- devtools/client/responsivedesign/test/head.js | 2 +- devtools/client/scratchpad/scratchpad.js | 7 ++ .../test/browser_scratchpad_files.js | 4 -- .../test/browser_scratchpad_modeline.js | 7 -- .../test/browser_scratchpad_recent_files.js | 6 -- .../test/browser_scratchpad_reset_undo.js | 6 -- .../browser_scratchpad_revert_to_saved.js | 6 -- devtools/client/shadereditor/shadereditor.js | 1 + devtools/client/shared/test/test-actor.js | 4 +- devtools/client/shared/widgets/TableWidget.js | 5 ++ devtools/client/webaudioeditor/includes.js | 1 + .../client/webaudioeditor/views/context.js | 5 ++ ...-properties-with-non-alphanumeric-names.js | 6 +- devtools/client/webide/content/webide.js | 10 +++ .../server/tests/mochitest/hello-actor.js | 2 +- .../tests/mochitest/test_registerActor.html | 2 +- devtools/server/tests/unit/hello-actor.js | 2 +- .../tests/unit/test_framebindings-02.js | 3 +- .../tests/unit/test_framebindings-05.js | 3 +- devtools/shared/apps/Devices.jsm | 5 ++ .../test/test_commands_registration.html | 1 - .../shared/webconsole/test/test_jsterm.html | 1 - devtools/shared/worker-loader.js | 2 +- ..._anonymousContent_append_after_reflow.html | 2 +- .../test/test_anonymousContent_style_csp.html | 2 +- dom/devicestorage/test/test_fs_remove.html | 2 +- dom/html/test/test_checked.html | 16 ++--- dom/ipc/preload.js | 4 +- dom/mobilemessage/gonk/WspPduHelper.jsm | 12 ++++ dom/plugins/test/unit/test_bug455213.js | 2 - dom/plugins/test/unit/test_bug813245.js | 2 - .../test/unit/test_nice_plugin_name.js | 3 - .../test/unit/test_persist_in_prefs.js | 2 - dom/telephony/gonk/TelephonyService.js | 6 ++ dom/tests/mochitest/chrome/489127.html | 2 +- .../mochitest/chrome/queryCaretRectUnix.html | 4 +- .../mochitest/chrome/queryCaretRectWin.html | 4 +- dom/tests/mochitest/chrome/selectAtPoint.html | 4 +- js/xpconnect/loader/XPCOMUtils.jsm | 11 +++ .../tests/unit/test_writeToGlobalPrototype.js | 2 +- .../chrome/test_session_form_data.html | 6 +- testing/marionette/driver.js | 10 +-- testing/marionette/listener.js | 4 +- testing/marionette/server.js | 2 +- testing/mochitest/b2g_start_script.js | 6 +- .../mochitest/tests/SimpleTest/EventUtils.js | 12 ++++ .../components/TalosPowersService.js | 2 +- toolkit/components/places/UnifiedComplete.js | 16 ++--- .../places/tests/unit/test_null_interfaces.js | 2 - .../thumbnails/BackgroundPageThumbs.jsm | 30 +++++--- .../test/browser_thumbnails_expiration.js | 3 +- toolkit/content/contentAreaUtils.js | 5 ++ toolkit/content/widgets/autocomplete.xml | 8 ++- toolkit/content/widgets/tabbox.xml | 8 ++- toolkit/modules/WindowsRegistry.jsm | 2 +- .../extensions/internal/GMPProvider.jsm | 1 + .../extensions/internal/XPIProvider.jsm | 1 + 100 files changed, 502 insertions(+), 246 deletions(-) diff --git a/accessible/tests/mochitest/relations.js b/accessible/tests/mochitest/relations.js index f34786df5a98..2f46c8d043cc 100644 --- a/accessible/tests/mochitest/relations.js +++ b/accessible/tests/mochitest/relations.js @@ -1,26 +1,26 @@ //////////////////////////////////////////////////////////////////////////////// // Constants -const RELATION_CONTROLLED_BY = nsIAccessibleRelation.RELATION_CONTROLLED_BY; -const RELATION_CONTROLLER_FOR = nsIAccessibleRelation.RELATION_CONTROLLER_FOR; -const RELATION_DEFAULT_BUTTON = nsIAccessibleRelation.RELATION_DEFAULT_BUTTON; -const RELATION_DESCRIBED_BY = nsIAccessibleRelation.RELATION_DESCRIBED_BY; -const RELATION_DESCRIPTION_FOR = nsIAccessibleRelation.RELATION_DESCRIPTION_FOR; -const RELATION_EMBEDDED_BY = nsIAccessibleRelation.RELATION_EMBEDDED_BY; -const RELATION_EMBEDS = nsIAccessibleRelation.RELATION_EMBEDS; -const RELATION_FLOWS_FROM = nsIAccessibleRelation.RELATION_FLOWS_FROM; -const RELATION_FLOWS_TO = nsIAccessibleRelation.RELATION_FLOWS_TO; -const RELATION_LABEL_FOR = nsIAccessibleRelation.RELATION_LABEL_FOR; -const RELATION_LABELLED_BY = nsIAccessibleRelation.RELATION_LABELLED_BY; -const RELATION_MEMBER_OF = nsIAccessibleRelation.RELATION_MEMBER_OF; -const RELATION_NODE_CHILD_OF = nsIAccessibleRelation.RELATION_NODE_CHILD_OF; -const RELATION_NODE_PARENT_OF = nsIAccessibleRelation.RELATION_NODE_PARENT_OF; -const RELATION_PARENT_WINDOW_OF = nsIAccessibleRelation.RELATION_PARENT_WINDOW_OF; -const RELATION_POPUP_FOR = nsIAccessibleRelation.RELATION_POPUP_FOR; -const RELATION_SUBWINDOW_OF = nsIAccessibleRelation.RELATION_SUBWINDOW_OF; -const RELATION_CONTAINING_DOCUMENT = nsIAccessibleRelation.RELATION_CONTAINING_DOCUMENT; -const RELATION_CONTAINING_TAB_PANE = nsIAccessibleRelation.RELATION_CONTAINING_TAB_PANE; -const RELATION_CONTAINING_APPLICATION = nsIAccessibleRelation.RELATION_CONTAINING_APPLICATION; +var RELATION_CONTROLLED_BY = nsIAccessibleRelation.RELATION_CONTROLLED_BY; +var RELATION_CONTROLLER_FOR = nsIAccessibleRelation.RELATION_CONTROLLER_FOR; +var RELATION_DEFAULT_BUTTON = nsIAccessibleRelation.RELATION_DEFAULT_BUTTON; +var RELATION_DESCRIBED_BY = nsIAccessibleRelation.RELATION_DESCRIBED_BY; +var RELATION_DESCRIPTION_FOR = nsIAccessibleRelation.RELATION_DESCRIPTION_FOR; +var RELATION_EMBEDDED_BY = nsIAccessibleRelation.RELATION_EMBEDDED_BY; +var RELATION_EMBEDS = nsIAccessibleRelation.RELATION_EMBEDS; +var RELATION_FLOWS_FROM = nsIAccessibleRelation.RELATION_FLOWS_FROM; +var RELATION_FLOWS_TO = nsIAccessibleRelation.RELATION_FLOWS_TO; +var RELATION_LABEL_FOR = nsIAccessibleRelation.RELATION_LABEL_FOR; +var RELATION_LABELLED_BY = nsIAccessibleRelation.RELATION_LABELLED_BY; +var RELATION_MEMBER_OF = nsIAccessibleRelation.RELATION_MEMBER_OF; +var RELATION_NODE_CHILD_OF = nsIAccessibleRelation.RELATION_NODE_CHILD_OF; +var RELATION_NODE_PARENT_OF = nsIAccessibleRelation.RELATION_NODE_PARENT_OF; +var RELATION_PARENT_WINDOW_OF = nsIAccessibleRelation.RELATION_PARENT_WINDOW_OF; +var RELATION_POPUP_FOR = nsIAccessibleRelation.RELATION_POPUP_FOR; +var RELATION_SUBWINDOW_OF = nsIAccessibleRelation.RELATION_SUBWINDOW_OF; +var RELATION_CONTAINING_DOCUMENT = nsIAccessibleRelation.RELATION_CONTAINING_DOCUMENT; +var RELATION_CONTAINING_TAB_PANE = nsIAccessibleRelation.RELATION_CONTAINING_TAB_PANE; +var RELATION_CONTAINING_APPLICATION = nsIAccessibleRelation.RELATION_CONTAINING_APPLICATION; //////////////////////////////////////////////////////////////////////////////// // General diff --git a/addon-sdk/source/test/fixtures/addon/bootstrap.js b/addon-sdk/source/test/fixtures/addon/bootstrap.js index 988927418268..9134b4d92860 100644 --- a/addon-sdk/source/test/fixtures/addon/bootstrap.js +++ b/addon-sdk/source/test/fixtures/addon/bootstrap.js @@ -6,4 +6,4 @@ const { utils: Cu } = Components; const {require} = Cu.import(`${ROOT}/toolkit/require.js`, {}); const {Bootstrap} = require(`${ROOT}/sdk/addon/bootstrap.js`); -const {startup, shutdown, install, uninstall} = new Bootstrap(); +var {startup, shutdown, install, uninstall} = new Bootstrap(); diff --git a/addon-sdk/source/test/test-content-script.js b/addon-sdk/source/test/test-content-script.js index 295a4cad505a..ecb7338941d0 100644 --- a/addon-sdk/source/test/test-content-script.js +++ b/addon-sdk/source/test/test-content-script.js @@ -727,7 +727,7 @@ exports["test requestAnimationFrame"] = createProxyTest("", function (helper) { exports["testGlobalScope"] = createProxyTest("", function (helper) { helper.createWorker( - 'let toplevelScope = true;' + + 'var toplevelScope = true;' + 'assert(window.toplevelScope, "variables in toplevel scope are set to `window` object");' + 'assert(this.toplevelScope, "variables in toplevel scope are set to `this` object");' + 'done();' diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index c3e933b338e8..2a1a574dec25 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -3722,6 +3722,8 @@ const BrowserSearch = { } }; +XPCOMUtils.defineConstant(this, "BrowserSearch", BrowserSearch); + function FillHistoryMenu(aParent) { // Lazily add the hover listeners on first showing and never remove them if (!aParent.hasStatusListener) { diff --git a/browser/base/content/test/general/healthreport_pingData.js b/browser/base/content/test/general/healthreport_pingData.js index e880c31538ac..1737baba13ef 100644 --- a/browser/base/content/test/general/healthreport_pingData.js +++ b/browser/base/content/test/general/healthreport_pingData.js @@ -1,4 +1,4 @@ -const TEST_PINGS = [ +var TEST_PINGS = [ { type: "test-telemetryArchive-1", payload: { foo: "bar" }, diff --git a/browser/base/content/urlbarBindings.xml b/browser/base/content/urlbarBindings.xml index 8c83f49aa116..a2cd28e10bc9 100644 --- a/browser/base/content/urlbarBindings.xml +++ b/browser/base/content/urlbarBindings.xml @@ -1594,9 +1594,11 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/. document.getElementById("addon-progress-notification-progresstext"); - let utils = {}; - Components.utils.import("resource://gre/modules/DownloadUtils.jsm", utils); - utils.DownloadUtils; + { + let utils = {}; + Components.utils.import("resource://gre/modules/DownloadUtils.jsm", utils); + utils.DownloadUtils; + } @@ -2676,11 +2678,13 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/. ]]> document.getAnonymousElementByAttribute(this, "anonid", "promo-message"); diff --git a/browser/components/customizableui/content/panelUI.js b/browser/components/customizableui/content/panelUI.js index d8722b2734d0..b03a44aca7a9 100644 --- a/browser/components/customizableui/content/panelUI.js +++ b/browser/components/customizableui/content/panelUI.js @@ -510,6 +510,8 @@ const PanelUI = { }, }; +XPCOMUtils.defineConstant(this, "PanelUI", PanelUI); + /** * Gets the currently selected locale for display. * @return the selected locale or "en-US" if none is selected diff --git a/browser/components/customizableui/test/browser_1096763_seen_widgets_post_reset.js b/browser/components/customizableui/test/browser_1096763_seen_widgets_post_reset.js index 7f4e0e28d326..b707ca10e3c4 100644 --- a/browser/components/customizableui/test/browser_1096763_seen_widgets_post_reset.js +++ b/browser/components/customizableui/test/browser_1096763_seen_widgets_post_reset.js @@ -9,17 +9,18 @@ add_task(function*() { defaultArea: CustomizableUI.AREA_NAVBAR }); + const kPrefCustomizationState = "browser.uiCustomization.state"; let bsPass = Cu.import("resource:///modules/CustomizableUI.jsm", {}); ok(bsPass.gSeenWidgets.has(BUTTONID), "Widget should be seen after createWidget is called."); CustomizableUI.reset(); ok(bsPass.gSeenWidgets.has(BUTTONID), "Widget should still be seen after reset."); - ok(!Services.prefs.prefHasUserValue(bsPass.kPrefCustomizationState), "Pref shouldn't be set right now, because that'd break undo."); + ok(!Services.prefs.prefHasUserValue(kPrefCustomizationState), "Pref shouldn't be set right now, because that'd break undo."); CustomizableUI.addWidgetToArea(BUTTONID, CustomizableUI.AREA_NAVBAR); gCustomizeMode.removeFromArea(document.getElementById(BUTTONID)); - let hasUserValue = Services.prefs.prefHasUserValue(bsPass.kPrefCustomizationState); + let hasUserValue = Services.prefs.prefHasUserValue(kPrefCustomizationState); ok(hasUserValue, "Pref should be set right now."); if (hasUserValue) { - let seenArray = JSON.parse(Services.prefs.getCharPref(bsPass.kPrefCustomizationState)).seen; + let seenArray = JSON.parse(Services.prefs.getCharPref(kPrefCustomizationState)).seen; isnot(seenArray.indexOf(BUTTONID), -1, "Widget should be in saved 'seen' list."); } }); diff --git a/browser/components/downloads/content/downloads.js b/browser/components/downloads/content/downloads.js index 276bdda3deda..de17c5d760bb 100644 --- a/browser/components/downloads/content/downloads.js +++ b/browser/components/downloads/content/downloads.js @@ -580,6 +580,8 @@ const DownloadsPanel = { }, }; +XPCOMUtils.defineConstant(this, "DownloadsPanel", DownloadsPanel); + //////////////////////////////////////////////////////////////////////////////// //// DownloadsOverlayLoader @@ -658,6 +660,8 @@ const DownloadsOverlayLoader = { }, }; +XPCOMUtils.defineConstant(this, "DownloadsOverlayLoader", DownloadsOverlayLoader); + //////////////////////////////////////////////////////////////////////////////// //// DownloadsView @@ -1004,6 +1008,8 @@ const DownloadsView = { }, } +XPCOMUtils.defineConstant(this, "DownloadsView", DownloadsView); + //////////////////////////////////////////////////////////////////////////////// //// DownloadsViewItem @@ -1142,6 +1148,8 @@ const DownloadsViewController = { } }; +XPCOMUtils.defineConstant(this, "DownloadsViewController", DownloadsViewController); + //////////////////////////////////////////////////////////////////////////////// //// DownloadsViewItemController @@ -1488,7 +1496,9 @@ const DownloadsSummary = { delete this._detailsNode; return this._detailsNode = node; } -} +}; + +XPCOMUtils.defineConstant(this, "DownloadsSummary", DownloadsSummary); //////////////////////////////////////////////////////////////////////////////// //// DownloadsFooter @@ -1542,3 +1552,5 @@ const DownloadsFooter = { return this._footerNode = node; } }; + +XPCOMUtils.defineConstant(this, "DownloadsFooter", DownloadsFooter); diff --git a/browser/components/downloads/content/indicator.js b/browser/components/downloads/content/indicator.js index 9261c4997386..b4df74c6067d 100644 --- a/browser/components/downloads/content/indicator.js +++ b/browser/components/downloads/content/indicator.js @@ -577,3 +577,8 @@ const DownloadsIndicatorView = { }, }; +Object.defineProperty(this, "DownloadsIndicatorView", { + value: DownloadsIndicatorView, + enumerable: true, + writable: false +}); diff --git a/browser/components/loop/modules/LoopRoomsCache.jsm b/browser/components/loop/modules/LoopRoomsCache.jsm index c1915723c755..16e37dd256b9 100644 --- a/browser/components/loop/modules/LoopRoomsCache.jsm +++ b/browser/components/loop/modules/LoopRoomsCache.jsm @@ -17,6 +17,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm this.EXPORTED_SYMBOLS = ["LoopRoomsCache"]; const LOOP_ROOMS_CACHE_FILENAME = "loopRoomsCache.json"; +XPCOMUtils.defineConstant(this, "LOOP_ROOMS_CACHE_FILENAME", LOOP_ROOMS_CACHE_FILENAME); /** * RoomsCache is a cache for saving simple rooms data to the disk in case we diff --git a/browser/components/loop/modules/MozLoopService.jsm b/browser/components/loop/modules/MozLoopService.jsm index ef63a91e2c46..7de2d97d5ff6 100644 --- a/browser/components/loop/modules/MozLoopService.jsm +++ b/browser/components/loop/modules/MozLoopService.jsm @@ -112,6 +112,14 @@ this.EXPORTED_SYMBOLS = ["MozLoopService", "LOOP_SESSION_TYPE", "TWO_WAY_MEDIA_CONN_LENGTH", "SHARING_STATE_CHANGE", "SHARING_ROOM_URL", "ROOM_CREATE", "ROOM_DELETE", "ROOM_CONTEXT_ADD"]; +XPCOMUtils.defineConstant(this, "LOOP_SESSION_TYPE", LOOP_SESSION_TYPE); +XPCOMUtils.defineConstant(this, "TWO_WAY_MEDIA_CONN_LENGTH", TWO_WAY_MEDIA_CONN_LENGTH); +XPCOMUtils.defineConstant(this, "SHARING_STATE_CHANGE", SHARING_STATE_CHANGE); +XPCOMUtils.defineConstant(this, "SHARING_ROOM_URL", SHARING_ROOM_URL); +XPCOMUtils.defineConstant(this, "ROOM_CREATE", ROOM_CREATE); +XPCOMUtils.defineConstant(this, "ROOM_DELETE", ROOM_DELETE); +XPCOMUtils.defineConstant(this, "ROOM_CONTEXT_ADD", ROOM_CONTEXT_ADD); + XPCOMUtils.defineLazyModuleGetter(this, "injectLoopAPI", "resource:///modules/loop/MozLoopAPI.jsm"); diff --git a/browser/components/sessionstore/test/browser_privatetabs.js b/browser/components/sessionstore/test/browser_privatetabs.js index 12d8a7bfe89e..7b296bbbf05d 100644 --- a/browser/components/sessionstore/test/browser_privatetabs.js +++ b/browser/components/sessionstore/test/browser_privatetabs.js @@ -1,10 +1,6 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ -var Imports = {}; -Cu.import("resource:///modules/sessionstore/SessionSaver.jsm", Imports); -var {SessionSaver} = Imports; - add_task(function cleanup() { info("Forgetting closed tabs"); while (ss.getClosedTabCount(window)) { diff --git a/browser/experiments/Experiments.jsm b/browser/experiments/Experiments.jsm index f91ab3778840..739ed5bb8fca 100644 --- a/browser/experiments/Experiments.jsm +++ b/browser/experiments/Experiments.jsm @@ -94,6 +94,7 @@ const TELEMETRY_LOG = { RECHECK: "RECHECK", }, }; +XPCOMUtils.defineConstant(this, "TELEMETRY_LOG", TELEMETRY_LOG); const gPrefs = new Preferences(PREF_BRANCH); const gPrefsTelemetry = new Preferences(PREF_BRANCH_TELEMETRY); diff --git a/browser/modules/Windows8WindowFrameColor.jsm b/browser/modules/Windows8WindowFrameColor.jsm index cb52ad62696d..429d970ca954 100644 --- a/browser/modules/Windows8WindowFrameColor.jsm +++ b/browser/modules/Windows8WindowFrameColor.jsm @@ -11,7 +11,7 @@ Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); var Registry = Cu.import("resource://gre/modules/WindowsRegistry.jsm").WindowsRegistry; -const Windows8WindowFrameColor = { +var Windows8WindowFrameColor = { _windowFrameColor: null, get: function() { diff --git a/devtools/client/canvasdebugger/canvasdebugger.js b/devtools/client/canvasdebugger/canvasdebugger.js index 11d5835034e9..c39bd04dc212 100644 --- a/devtools/client/canvasdebugger/canvasdebugger.js +++ b/devtools/client/canvasdebugger/canvasdebugger.js @@ -77,6 +77,7 @@ const EVENTS = { SOURCE_SHOWN_IN_JS_DEBUGGER: "CanvasDebugger:SourceShownInJsDebugger", SOURCE_NOT_FOUND_IN_JS_DEBUGGER: "CanvasDebugger:SourceNotFoundInJsDebugger" }; +XPCOMUtils.defineConstant(this, "EVENTS", EVENTS); const HTML_NS = "http://www.w3.org/1999/xhtml"; const STRINGS_URI = "chrome://browser/locale/devtools/canvasdebugger.properties"; diff --git a/devtools/client/debugger/debugger-controller.js b/devtools/client/debugger/debugger-controller.js index cd1fee18e070..6fc0137b6ff2 100644 --- a/devtools/client/debugger/debugger-controller.js +++ b/devtools/client/debugger/debugger-controller.js @@ -104,6 +104,7 @@ Cu.import("resource:///modules/devtools/client/shared/widgets/ViewHelpers.jsm"); Cu.import("resource:///modules/devtools/client/shared/browser-loader.js"); const require = BrowserLoader("resource:///modules/devtools/client/debugger/", this).require; +XPCOMUtils.defineConstant(this, "require", require); const {TargetFactory} = require("devtools/client/framework/target"); const {Toolbox} = require("devtools/client/framework/toolbox"); @@ -114,6 +115,8 @@ const DebuggerEditor = require("devtools/client/sourceeditor/debugger"); const {Tooltip} = require("devtools/client/shared/widgets/Tooltip"); const FastListWidget = require("devtools/client/shared/widgets/FastListWidget"); +XPCOMUtils.defineConstant(this, "EVENTS", EVENTS); + XPCOMUtils.defineLazyModuleGetter(this, "Task", "resource://gre/modules/Task.jsm"); diff --git a/devtools/client/debugger/debugger-view.js b/devtools/client/debugger/debugger-view.js index 1dcf5d5aaa8f..47afbe9c9e07 100644 --- a/devtools/client/debugger/debugger-view.js +++ b/devtools/client/debugger/debugger-view.js @@ -49,6 +49,19 @@ const services = { const EventListenersView = require('./content/views/event-listeners-view'); const actions = require('./content/actions/event-listeners'); +Object.defineProperties(this, { + "store": { + value: store, + enumerable: true, + writable: false + }, + "services": { + value: services, + enumerable: true, + writable: false + } +}); + /** * Object defining the debugger view components. */ diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_break-on-next-console.js b/devtools/client/debugger/test/mochitest/browser_dbg_break-on-next-console.js index ff259780cc2e..4fe42eb6438f 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_break-on-next-console.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_break-on-next-console.js @@ -40,11 +40,13 @@ function test() { let updatedFrame = yield waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES); let variables = gDebugger.DebuggerView.Variables; - is(variables._store.length, 2, "Correct number of scopes available"); + is(variables._store.length, 3, "Correct number of scopes available"); is(variables.getScopeAtIndex(0).name, "With scope [Object]", "Paused with correct scope (0)"); - is(variables.getScopeAtIndex(1).name, "Global scope [Window]", + is(variables.getScopeAtIndex(1).name, "Block scope", "Paused with correct scope (1)"); + is(variables.getScopeAtIndex(2).name, "Global scope [Window]", + "Paused with correct scope (2)"); let onceResumed = gTarget.once("thread-resumed"); EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger); diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_break-on-next.js b/devtools/client/debugger/test/mochitest/browser_dbg_break-on-next.js index af7064ee8c62..edded224faa2 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_break-on-next.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_break-on-next.js @@ -49,13 +49,15 @@ function test() { let updatedFrame = yield waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES); let variables = gDebugger.DebuggerView.Variables; - is(variables._store.length, 3, "Correct number of scopes available"); + is(variables._store.length, 4, "Correct number of scopes available"); is(variables.getScopeAtIndex(0).name, "Function scope [interval<]", "Paused with correct scope (0)"); is(variables.getScopeAtIndex(1).name, "Block scope", "Paused with correct scope (1)"); - is(variables.getScopeAtIndex(2).name, "Global scope [Window]", + is(variables.getScopeAtIndex(2).name, "Block scope", "Paused with correct scope (2)"); + is(variables.getScopeAtIndex(3).name, "Global scope [Window]", + "Paused with correct scope (3)"); yield evalInTab(gTab, "clearInterval(interval)"); let onceResumed = gTarget.once("thread-resumed"); @@ -76,15 +78,21 @@ function test() { let updatedFrame = yield waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES); let variables = gDebugger.DebuggerView.Variables; - is(variables._store.length, 4, "Correct number of scopes available"); + is(variables._store.length, 6, "Correct number of scopes available"); is(variables.getScopeAtIndex(0).name, "Function scope [onclick]", "Paused with correct scope (0)"); - is(variables.getScopeAtIndex(1).name, "With scope [HTMLButtonElement]", + // Non-syntactic lexical scope introduced by non-syntactic scope chain. + is(variables.getScopeAtIndex(1).name, "Block scope", "Paused with correct scope (1)"); - is(variables.getScopeAtIndex(2).name, "With scope [HTMLDocument]", + is(variables.getScopeAtIndex(2).name, "With scope [HTMLButtonElement]", "Paused with correct scope (2)"); - is(variables.getScopeAtIndex(3).name, "Global scope [Window]", + is(variables.getScopeAtIndex(3).name, "With scope [HTMLDocument]", "Paused with correct scope (3)"); + // Global lexical scope. + is(variables.getScopeAtIndex(4).name, "Block scope", + "Paused with correct scope (4)"); + is(variables.getScopeAtIndex(5).name, "Global scope [Window]", + "Paused with correct scope (5)"); let onceResumed = gTarget.once("thread-resumed"); EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger); diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_pause-exceptions-01.js b/devtools/client/debugger/test/mochitest/browser_dbg_pause-exceptions-01.js index edfb63dc161e..bb0775590ea7 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_pause-exceptions-01.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_pause-exceptions-01.js @@ -53,8 +53,8 @@ function testPauseOnExceptionsDisabled() { is(gFrames.itemCount, 1, "Should have one frame."); - is(gVariables._store.length, 3, - "Should have three scopes."); + is(gVariables._store.length, 4, + "Should have four scopes."); is(innerNodes[0].querySelector(".name").getAttribute("value"), "this", "Should have the right property name for 'this'."); @@ -96,8 +96,8 @@ function testPauseOnExceptionsEnabled() { is(gFrames.itemCount, 1, "Should have one frame."); - is(gVariables._store.length, 3, - "Should have three scopes."); + is(gVariables._store.length, 4, + "Should have four scopes."); is(innerNodes[0].querySelector(".name").getAttribute("value"), "", "Should have the right property name for ."); @@ -117,8 +117,8 @@ function testPauseOnExceptionsEnabled() { is(gFrames.itemCount, 1, "Should have one frame."); - is(gVariables._store.length, 3, - "Should have three scopes."); + is(gVariables._store.length, 4, + "Should have four scopes."); is(innerNodes[0].querySelector(".name").getAttribute("value"), "this", "Should have the right property name for 'this'."); diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_pause-exceptions-02.js b/devtools/client/debugger/test/mochitest/browser_dbg_pause-exceptions-02.js index f44f6c3ddb48..547e86b5c273 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_pause-exceptions-02.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_pause-exceptions-02.js @@ -52,8 +52,8 @@ function testPauseOnExceptionsAfterReload() { is(gFrames.itemCount, 1, "Should have one frame."); - is(gVariables._store.length, 3, - "Should have three scopes."); + is(gVariables._store.length, 4, + "Should have four scopes."); is(innerNodes[0].querySelector(".name").getAttribute("value"), "", "Should have the right property name for ."); @@ -73,8 +73,8 @@ function testPauseOnExceptionsAfterReload() { is(gFrames.itemCount, 1, "Should have one frame."); - is(gVariables._store.length, 3, - "Should have three scopes."); + is(gVariables._store.length, 4, + "Should have four scopes."); is(innerNodes[0].querySelector(".name").getAttribute("value"), "this", "Should have the right property name for 'this'."); diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-06.js b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-06.js index fa6901d081bd..f02a03ff386e 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-06.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-06.js @@ -7,7 +7,7 @@ const TAB_URL = EXAMPLE_URL + "doc_promise.html"; -const test = Task.async(function* () { +var test = Task.async(function* () { const [tab,, panel] = yield initDebugger(TAB_URL); yield ensureSourceIs(panel, "doc_promise.html", true); diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-01.js b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-01.js index b3f1bd49ab94..cc864c9a04a8 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-01.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-01.js @@ -44,7 +44,8 @@ function testVariablesAndPropertiesFiltering() { let localScope = gVariables.getScopeAtIndex(0); let withScope = gVariables.getScopeAtIndex(1); let functionScope = gVariables.getScopeAtIndex(2); - let globalScope = gVariables.getScopeAtIndex(3); + let globalLexicalScope = gVariables.getScopeAtIndex(3); + let globalScope = gVariables.getScopeAtIndex(4); let protoVar = localScope.get("__proto__"); let constrVar = protoVar.get("constructor"); let proto2Var = constrVar.get("__proto__"); @@ -57,6 +58,8 @@ function testVariablesAndPropertiesFiltering() { "The withScope should be expanded."); is(functionScope.expanded, true, "The functionScope should be expanded."); + is(globalLexicalScope.expanded, true, + "The globalLexicalScope should be expanded."); is(globalScope.expanded, true, "The globalScope should be expanded."); @@ -75,6 +78,8 @@ function testVariablesAndPropertiesFiltering() { "There should be 0 variables displayed in the with scope."); is(functionScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 0, "There should be 0 variables displayed in the function scope."); + is(globalLexicalScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 0, + "There should be 0 variables displayed in the global lexical scope."); is(globalScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 0, "There should be 0 variables displayed in the global scope."); @@ -82,6 +87,8 @@ function testVariablesAndPropertiesFiltering() { "There should be 0 properties displayed in the with scope."); is(functionScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 0, "There should be 0 properties displayed in the function scope."); + is(globalLexicalScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 0, + "There should be 0 properties displayed in the global lexical scope."); is(globalScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 0, "There should be 0 properties displayed in the global scope."); @@ -106,6 +113,7 @@ function testVariablesAndPropertiesFiltering() { localScope.collapse(); withScope.collapse(); functionScope.collapse(); + globalLexicalScope.collapse(); globalScope.collapse(); protoVar.collapse(); constrVar.collapse(); @@ -118,6 +126,8 @@ function testVariablesAndPropertiesFiltering() { "The withScope should not be expanded."); is(functionScope.expanded, false, "The functionScope should not be expanded."); + is(globalLexicalScope.expanded, false, + "The globalLexicalScope should not be expanded."); is(globalScope.expanded, false, "The globalScope should not be expanded."); @@ -145,14 +155,17 @@ function prepareVariablesAndProperties() { let localScope = gVariables.getScopeAtIndex(0); let withScope = gVariables.getScopeAtIndex(1); let functionScope = gVariables.getScopeAtIndex(2); - let globalScope = gVariables.getScopeAtIndex(3); + let globalLexicalScope = gVariables.getScopeAtIndex(3); + let globalScope = gVariables.getScopeAtIndex(4); is(localScope.expanded, true, "The localScope should be expanded."); is(withScope.expanded, false, "The withScope should not be expanded yet."); is(functionScope.expanded, false, - "The functionScope should not be expanded yet."); + "The functionScope should not be expanded yet."); + is(globalLexicalScope.expanded, false, + "The globalLexicalScope should not be expanded yet."); is(globalScope.expanded, false, "The globalScope should not be expanded yet."); @@ -164,7 +177,9 @@ function prepareVariablesAndProperties() { is(withScope.expanded, true, "The withScope should now be expanded."); is(functionScope.expanded, true, - "The functionScope should now be expanded."); + "The functionScope should now be expanded."); + is(globalLexicalScope.expanded, true, + "The globalLexicalScope should be expanded."); is(globalScope.expanded, true, "The globalScope should now be expanded."); @@ -206,6 +221,7 @@ function prepareVariablesAndProperties() { withScope.expand(); functionScope.expand(); + globalLexicalScope.expand(); globalScope.expand(); return deferred.promise; diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-02.js b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-02.js index 240147089a1b..80c9095327b9 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-02.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-02.js @@ -44,7 +44,8 @@ function testVariablesAndPropertiesFiltering() { let localScope = gVariables.getScopeAtIndex(0); let withScope = gVariables.getScopeAtIndex(1); let functionScope = gVariables.getScopeAtIndex(2); - let globalScope = gVariables.getScopeAtIndex(3); + let globalLexicalScope = gVariables.getScopeAtIndex(3); + let globalScope = gVariables.getScopeAtIndex(4); let protoVar = localScope.get("__proto__"); let constrVar = protoVar.get("constructor"); let proto2Var = constrVar.get("__proto__"); @@ -57,6 +58,8 @@ function testVariablesAndPropertiesFiltering() { "The withScope should be expanded."); is(functionScope.expanded, true, "The functionScope should be expanded."); + is(globalLexicalScope.expanded, true, + "The globalScope should be expanded."); is(globalScope.expanded, true, "The globalScope should be expanded."); @@ -75,6 +78,8 @@ function testVariablesAndPropertiesFiltering() { "There should be 0 variables displayed in the with scope."); is(functionScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 0, "There should be 0 variables displayed in the function scope."); + is(globalLexicalScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 0, + "There should be no variables displayed in the global lexical scope."); is(globalScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 0, "There should be no variables displayed in the global scope."); @@ -84,6 +89,8 @@ function testVariablesAndPropertiesFiltering() { "There should be 0 properties displayed in the with scope."); is(functionScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 0, "There should be 0 properties displayed in the function scope."); + is(globalLexicalScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 0, + "There should be 0 properties displayed in the global lexical scope."); is(globalScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 0, "There should be 0 properties displayed in the global scope."); @@ -113,6 +120,7 @@ function testVariablesAndPropertiesFiltering() { localScope.collapse(); withScope.collapse(); functionScope.collapse(); + globalLexicalScope.collapse(); globalScope.collapse(); protoVar.collapse(); constrVar.collapse(); @@ -125,6 +133,8 @@ function testVariablesAndPropertiesFiltering() { "The withScope should not be expanded."); is(functionScope.expanded, false, "The functionScope should not be expanded."); + is(globalLexicalScope.expanded, false, + "The globalScope should not be expanded."); is(globalScope.expanded, false, "The globalScope should not be expanded."); @@ -153,7 +163,8 @@ function prepareVariablesAndProperties() { let localScope = gVariables.getScopeAtIndex(0); let withScope = gVariables.getScopeAtIndex(1); let functionScope = gVariables.getScopeAtIndex(2); - let globalScope = gVariables.getScopeAtIndex(3); + let globalLexicalScope = gVariables.getScopeAtIndex(3); + let globalScope = gVariables.getScopeAtIndex(4); is(localScope.expanded, true, "The localScope should be expanded."); @@ -161,6 +172,8 @@ function prepareVariablesAndProperties() { "The withScope should not be expanded yet."); is(functionScope.expanded, false, "The functionScope should not be expanded yet."); + is(globalLexicalScope.expanded, false, + "The globalScope should not be expanded yet."); is(globalScope.expanded, false, "The globalScope should not be expanded yet."); @@ -173,6 +186,8 @@ function prepareVariablesAndProperties() { "The withScope should now be expanded."); is(functionScope.expanded, true, "The functionScope should now be expanded."); + is(globalLexicalScope.expanded, true, + "The globalScope should now be expanded."); is(globalScope.expanded, true, "The globalScope should now be expanded."); @@ -214,6 +229,7 @@ function prepareVariablesAndProperties() { withScope.expand(); functionScope.expand(); + globalLexicalScope.expand(); globalScope.expand(); return deferred.promise; diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-03.js b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-03.js index 88f5ff8cb99f..a444b7e60a7e 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-03.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-03.js @@ -43,7 +43,8 @@ function testVariablesAndPropertiesFiltering() { let localScope = gVariables.getScopeAtIndex(0); let withScope = gVariables.getScopeAtIndex(1); let functionScope = gVariables.getScopeAtIndex(2); - let globalScope = gVariables.getScopeAtIndex(3); + let globalLexicalScope = gVariables.getScopeAtIndex(3); + let globalScope = gVariables.getScopeAtIndex(4); function testFiltered() { is(localScope.expanded, true, @@ -52,6 +53,8 @@ function testVariablesAndPropertiesFiltering() { "The withScope should be expanded."); is(functionScope.expanded, true, "The functionScope should be expanded."); + is(globalLexicalScope.expanded, true, + "The globalScope should be expanded."); is(globalScope.expanded, true, "The globalScope should be expanded."); @@ -61,6 +64,8 @@ function testVariablesAndPropertiesFiltering() { "There should be 0 variables displayed in the with scope."); is(functionScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 0, "There should be 0 variables displayed in the function scope."); + is(globalLexicalScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 0, + "There should be 0 variables displayed in the global scope."); is(globalScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 0, "There should be 0 variables displayed in the global scope."); @@ -70,6 +75,8 @@ function testVariablesAndPropertiesFiltering() { "There should be 0 properties displayed in the with scope."); is(functionScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 0, "There should be 0 properties displayed in the function scope."); + is(globalLexicalScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 0, + "There should be 0 properties displayed in the global scope."); is(globalScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 0, "There should be 0 properties displayed in the global scope."); } @@ -86,6 +93,7 @@ function testVariablesAndPropertiesFiltering() { localScope.collapse(); withScope.collapse(); functionScope.collapse(); + globalLexicalScope.collapse(); globalScope.collapse(); is(localScope.expanded, false, @@ -94,6 +102,8 @@ function testVariablesAndPropertiesFiltering() { "The withScope should not be expanded."); is(functionScope.expanded, false, "The functionScope should not be expanded."); + is(globalLexicalScope.expanded, false, + "The globalScope should not be expanded."); is(globalScope.expanded, false, "The globalScope should not be expanded."); @@ -115,7 +125,8 @@ function prepareVariablesAndProperties() { let localScope = gVariables.getScopeAtIndex(0); let withScope = gVariables.getScopeAtIndex(1); let functionScope = gVariables.getScopeAtIndex(2); - let globalScope = gVariables.getScopeAtIndex(3); + let globalLexicalScope = gVariables.getScopeAtIndex(3); + let globalScope = gVariables.getScopeAtIndex(4); is(localScope.expanded, true, "The localScope should be expanded."); @@ -123,6 +134,8 @@ function prepareVariablesAndProperties() { "The withScope should not be expanded yet."); is(functionScope.expanded, false, "The functionScope should not be expanded yet."); + is(globalLexicalScope.expanded, false, + "The globalScope should not be expanded yet."); is(globalScope.expanded, false, "The globalScope should not be expanded yet."); @@ -135,6 +148,8 @@ function prepareVariablesAndProperties() { "The withScope should now be expanded."); is(functionScope.expanded, true, "The functionScope should now be expanded."); + is(globalLexicalScope.expanded, true, + "The globalScope should now be expanded."); is(globalScope.expanded, true, "The globalScope should now be expanded."); @@ -143,6 +158,7 @@ function prepareVariablesAndProperties() { withScope.expand(); functionScope.expand(); + globalLexicalScope.expand(); globalScope.expand(); return deferred.promise; diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-04.js b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-04.js index 1eb4748efbab..ed69dbc6f831 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-04.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-04.js @@ -44,108 +44,110 @@ function testVariablesAndPropertiesFiltering() { let localScope = gVariables.getScopeAtIndex(0); let withScope = gVariables.getScopeAtIndex(1); let functionScope = gVariables.getScopeAtIndex(2); - let globalScope = gVariables.getScopeAtIndex(3); + let globalLexicalScope = gVariables.getScopeAtIndex(3); + let globalScope = gVariables.getScopeAtIndex(4); let step = 0; let tests = [ function() { - assertExpansion([true, false, false, false]); + assertExpansion([true, false, false, false, false]); EventUtils.sendKey("RETURN", gDebugger); }, function() { - assertExpansion([true, false, false, false]); + assertExpansion([true, false, false, false, false]); EventUtils.sendKey("RETURN", gDebugger); }, function() { - assertExpansion([true, false, false, false]); + assertExpansion([true, false, false, false, false]); gEditor.focus(); }, function() { - assertExpansion([true, false, false, false]); + assertExpansion([true, false, false, false, false]); typeText(gSearchBox, "*"); }, function() { - assertExpansion([true, true, true, true]); + assertExpansion([true, true, true, true, true]); EventUtils.sendKey("RETURN", gDebugger); }, function() { - assertExpansion([true, true, true, true]); + assertExpansion([true, true, true, true, true]); EventUtils.sendKey("RETURN", gDebugger); }, function() { - assertExpansion([true, true, true, true]); + assertExpansion([true, true, true, true, true]); gEditor.focus(); }, function() { - assertExpansion([true, true, true, true]); + assertExpansion([true, true, true, true, true]); backspaceText(gSearchBox, 1); }, function() { - assertExpansion([true, true, true, true]); + assertExpansion([true, true, true, true, true]); EventUtils.sendKey("RETURN", gDebugger); }, function() { - assertExpansion([true, true, true, true]); + assertExpansion([true, true, true, true, true]); EventUtils.sendKey("RETURN", gDebugger); }, function() { - assertExpansion([true, true, true, true]); + assertExpansion([true, true, true, true, true]); gEditor.focus(); }, function() { - assertExpansion([true, true, true, true]); + assertExpansion([true, true, true, true, true]); localScope.collapse(); withScope.collapse(); functionScope.collapse(); + globalLexicalScope.collapse(); globalScope.collapse(); }, function() { - assertExpansion([false, false, false, false]); + assertExpansion([false, false, false, false, false]); EventUtils.sendKey("RETURN", gDebugger); }, function() { - assertExpansion([false, false, false, false]); + assertExpansion([false, false, false, false, false]); EventUtils.sendKey("RETURN", gDebugger); }, function() { - assertExpansion([false, false, false, false]); + assertExpansion([false, false, false, false, false]); gEditor.focus(); }, function() { - assertExpansion([false, false, false, false]); + assertExpansion([false, false, false, false, false]); clearText(gSearchBox); typeText(gSearchBox, "*"); }, function() { - assertExpansion([true, true, true, true]); + assertExpansion([true, true, true, true, true]); EventUtils.sendKey("RETURN", gDebugger); }, function() { - assertExpansion([true, true, true, true]); + assertExpansion([true, true, true, true, true]); EventUtils.sendKey("RETURN", gDebugger); }, function() { - assertExpansion([true, true, true, true]); + assertExpansion([true, true, true, true, true]); gEditor.focus(); }, function() { - assertExpansion([true, true, true, true]); + assertExpansion([true, true, true, true, true]); backspaceText(gSearchBox, 1); }, function() { - assertExpansion([true, true, true, true]); + assertExpansion([true, true, true, true, true]); EventUtils.sendKey("RETURN", gDebugger); }, function() { - assertExpansion([true, true, true, true]); + assertExpansion([true, true, true, true, true]); EventUtils.sendKey("RETURN", gDebugger); }, function() { - assertExpansion([true, true, true, true]); + assertExpansion([true, true, true, true, true]); gEditor.focus(); }, function() { - assertExpansion([true, true, true, true]); + assertExpansion([true, true, true, true, true]); } ]; @@ -162,8 +164,12 @@ function testVariablesAndPropertiesFiltering() { "The functionScope should " + (aFlags[2] ? "" : "not ") + "be expanded at this point (" + step + ")."); - is(globalScope.expanded, aFlags[3], - "The globalScope should " + (aFlags[3] ? "" : "not ") + + is(globalLexicalScope.expanded, aFlags[3], + "The globalLexicalScope should " + (aFlags[3] ? "" : "not ") + + "be expanded at this point (" + step + ")."); + + is(globalScope.expanded, aFlags[4], + "The globalScope should " + (aFlags[4] ? "" : "not ") + "be expanded at this point (" + step + ")."); step++; @@ -178,7 +184,8 @@ function prepareVariablesAndProperties() { let localScope = gVariables.getScopeAtIndex(0); let withScope = gVariables.getScopeAtIndex(1); let functionScope = gVariables.getScopeAtIndex(2); - let globalScope = gVariables.getScopeAtIndex(3); + let globalLexicalScope = gVariables.getScopeAtIndex(3); + let globalScope = gVariables.getScopeAtIndex(4); is(localScope.expanded, true, "The localScope should be expanded."); @@ -186,6 +193,8 @@ function prepareVariablesAndProperties() { "The withScope should not be expanded yet."); is(functionScope.expanded, false, "The functionScope should not be expanded yet."); + is(globalLexicalScope.expanded, false, + "The globalLexicalScope should not be expanded yet."); is(globalScope.expanded, false, "The globalScope should not be expanded yet."); @@ -198,11 +207,14 @@ function prepareVariablesAndProperties() { "The withScope should now be expanded."); is(functionScope.expanded, true, "The functionScope should now be expanded."); + is(globalLexicalScope.expanded, true, + "The globalLexicalScope should now be expanded."); is(globalScope.expanded, true, "The globalScope should now be expanded."); withScope.collapse(); functionScope.collapse(); + globalLexicalScope.collapse(); globalScope.collapse(); deferred.resolve(); @@ -210,6 +222,7 @@ function prepareVariablesAndProperties() { withScope.expand(); functionScope.expand(); + globalLexicalScope.expand(); globalScope.expand(); return deferred.promise; diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-05.js b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-05.js index 8d24fb300ac4..b1ee7d217b37 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-05.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-05.js @@ -43,17 +43,18 @@ function testVariablesAndPropertiesFiltering() { let localScope = gVariables.getScopeAtIndex(0); let withScope = gVariables.getScopeAtIndex(1); let functionScope = gVariables.getScopeAtIndex(2); - let globalScope = gVariables.getScopeAtIndex(3); + let globalLexicalScope = gVariables.getScopeAtIndex(3); + let globalScope = gVariables.getScopeAtIndex(4); let step = 0; let tests = [ function() { - assertScopeExpansion([true, false, false, false]); + assertScopeExpansion([true, false, false, false, false]); typeText(gSearchBox, "*arguments"); }, function() { - assertScopeExpansion([true, true, true, true]); - assertVariablesCountAtLeast([0, 0, 1, 0]); + assertScopeExpansion([true, true, true, true, true]); + assertVariablesCountAtLeast([0, 0, 1, 0, 0]); is(functionScope.target.querySelectorAll(".variables-view-variable:not([unmatched]) > .title > .name")[0].getAttribute("value"), "arguments", "The arguments pseudoarray should be visible."); @@ -63,8 +64,8 @@ function testVariablesAndPropertiesFiltering() { backspaceText(gSearchBox, 6); }, function() { - assertScopeExpansion([true, true, true, true]); - assertVariablesCountAtLeast([0, 0, 1, 1]); + assertScopeExpansion([true, true, true, true, true]); + assertVariablesCountAtLeast([0, 0, 1, 0, 1]); is(functionScope.target.querySelectorAll(".variables-view-variable:not([unmatched]) > .title > .name")[0].getAttribute("value"), "arguments", "The arguments pseudoarray should be visible."); @@ -79,8 +80,8 @@ function testVariablesAndPropertiesFiltering() { backspaceText(gSearchBox, 2); }, function() { - assertScopeExpansion([true, true, true, true]); - assertVariablesCountAtLeast([0, 1, 3, 1]); + assertScopeExpansion([true, true, true, true, true]); + assertVariablesCountAtLeast([0, 1, 3, 0, 1]); is(functionScope.target.querySelectorAll(".variables-view-variable:not([unmatched]) > .title > .name")[0].getAttribute("value"), "aNumber", "The aNumber param should be visible."); @@ -100,8 +101,8 @@ function testVariablesAndPropertiesFiltering() { backspaceText(gSearchBox, 1); }, function() { - assertScopeExpansion([true, true, true, true]); - assertVariablesCountAtLeast([4, 1, 3, 1]); + assertScopeExpansion([true, true, true, true, true]); + assertVariablesCountAtLeast([4, 1, 3, 0, 1]); is(localScope.target.querySelectorAll(".variables-view-variable:not([unmatched]) > .title > .name")[0].getAttribute("value"), "this", "The this reference should be visible."); @@ -153,8 +154,12 @@ function testVariablesAndPropertiesFiltering() { "The functionScope should " + (aFlags[2] ? "" : "not ") + "be expanded at this point (" + step + ")."); - is(globalScope.expanded, aFlags[3], - "The globalScope should " + (aFlags[3] ? "" : "not ") + + is(globalLexicalScope.expanded, aFlags[3], + "The globalLexicalScope should " + (aFlags[3] ? "" : "not ") + + "be expanded at this point (" + step + ")."); + + is(globalScope.expanded, aFlags[4], + "The globalScope should " + (aFlags[4] ? "" : "not ") + "be expanded at this point (" + step + ")."); } @@ -171,8 +176,12 @@ function testVariablesAndPropertiesFiltering() { "There should be " + aCounts[2] + " variable displayed in the function scope (" + step + ")."); - ok(globalScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length >= aCounts[3], + ok(globalLexicalScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length >= aCounts[3], "There should be " + aCounts[3] + + " variable displayed in the global scope (" + step + ")."); + + ok(globalScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length >= aCounts[4], + "There should be " + aCounts[4] + " variable displayed in the global scope (" + step + ")."); step++; @@ -187,7 +196,8 @@ function prepareVariablesAndProperties() { let localScope = gVariables.getScopeAtIndex(0); let withScope = gVariables.getScopeAtIndex(1); let functionScope = gVariables.getScopeAtIndex(2); - let globalScope = gVariables.getScopeAtIndex(3); + let globalLexicalScope = gVariables.getScopeAtIndex(3); + let globalScope = gVariables.getScopeAtIndex(4); is(localScope.expanded, true, "The localScope should be expanded."); @@ -195,6 +205,8 @@ function prepareVariablesAndProperties() { "The withScope should not be expanded yet."); is(functionScope.expanded, false, "The functionScope should not be expanded yet."); + is(globalLexicalScope.expanded, false, + "The globalScope should not be expanded yet."); is(globalScope.expanded, false, "The globalScope should not be expanded yet."); @@ -207,11 +219,14 @@ function prepareVariablesAndProperties() { "The withScope should now be expanded."); is(functionScope.expanded, true, "The functionScope should now be expanded."); + is(globalLexicalScope.expanded, true, + "The globalScope should now be expanded."); is(globalScope.expanded, true, "The globalScope should now be expanded."); withScope.collapse(); functionScope.collapse(); + globalLexicalScope.collapse(); globalScope.collapse(); deferred.resolve(); @@ -219,6 +234,7 @@ function prepareVariablesAndProperties() { withScope.expand(); functionScope.expand(); + globalLexicalScope.expand(); globalScope.expand(); return deferred.promise; diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-frame-parameters-01.js b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-frame-parameters-01.js index 320ee4104d1e..f175f933299b 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-frame-parameters-01.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-frame-parameters-01.js @@ -35,27 +35,35 @@ function test() { function initialChecks() { let scopeNodes = gDebugger.document.querySelectorAll(".variables-view-scope"); - is(scopeNodes.length, 2, - "There should be 2 scopes available."); + is(scopeNodes.length, 3, + "There should be 3 scopes available."); ok(scopeNodes[0].querySelector(".name").getAttribute("value").includes("[test]"), "The local scope should be properly identified."); - ok(scopeNodes[1].querySelector(".name").getAttribute("value").includes("[Window]"), + ok(scopeNodes[1].querySelector(".name").getAttribute("value").includes("Block"), + "The global lexical scope should be properly identified."); + ok(scopeNodes[2].querySelector(".name").getAttribute("value").includes("[Window]"), "The global scope should be properly identified."); is(gVariables.getScopeAtIndex(0).target, scopeNodes[0], "getScopeAtIndex(0) didn't return the expected scope."); is(gVariables.getScopeAtIndex(1).target, scopeNodes[1], "getScopeAtIndex(1) didn't return the expected scope."); + is(gVariables.getScopeAtIndex(2).target, scopeNodes[2], + "getScopeAtIndex(2) didn't return the expected scope."); is(gVariables.getItemForNode(scopeNodes[0]).target, scopeNodes[0], "getItemForNode([0]) didn't return the expected scope."); is(gVariables.getItemForNode(scopeNodes[1]).target, scopeNodes[1], "getItemForNode([1]) didn't return the expected scope."); + is(gVariables.getItemForNode(scopeNodes[2]).target, scopeNodes[2], + "getItemForNode([2]) didn't return the expected scope."); is(gVariables.getItemForNode(scopeNodes[0]).expanded, true, "The local scope should be expanded by default."); is(gVariables.getItemForNode(scopeNodes[1]).expanded, false, + "The global lexical scope should not be collapsed by default."); + is(gVariables.getItemForNode(scopeNodes[2]).expanded, false, "The global scope should not be collapsed by default."); } diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-frame-parameters-03.js b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-frame-parameters-03.js index 7b0768138766..2866c2ce1900 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-frame-parameters-03.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-frame-parameters-03.js @@ -38,7 +38,7 @@ function test() { function expandGlobalScope() { let deferred = promise.defer(); - let globalScope = gVariables.getScopeAtIndex(1); + let globalScope = gVariables.getScopeAtIndex(2); is(globalScope.expanded, false, "The global scope should not be expanded by default."); @@ -52,7 +52,7 @@ function expandGlobalScope() { } function testGlobalScope() { - let globalScope = gVariables.getScopeAtIndex(1); + let globalScope = gVariables.getScopeAtIndex(2); is(globalScope.expanded, true, "The global scope should now be expanded."); @@ -92,7 +92,7 @@ function testGlobalScope() { function expandWindowVariable() { let deferred = promise.defer(); - let windowVar = gVariables.getScopeAtIndex(1).get("window"); + let windowVar = gVariables.getScopeAtIndex(2).get("window"); is(windowVar.expanded, false, "The window variable should not be expanded by default."); @@ -106,7 +106,7 @@ function expandWindowVariable() { } function testWindowVariable() { - let windowVar = gVariables.getScopeAtIndex(1).get("window"); + let windowVar = gVariables.getScopeAtIndex(2).get("window"); is(windowVar.expanded, true, "The window variable should now be expanded."); diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-override-01.js b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-override-01.js index 84391a08fe8e..3b7c08977c8f 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-override-01.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-override-01.js @@ -21,11 +21,13 @@ function test() { let firstScope = variables.getScopeAtIndex(0); let secondScope = variables.getScopeAtIndex(1); let thirdScope = variables.getScopeAtIndex(2); - let globalScope = variables.getScopeAtIndex(3); + let globalLexicalScope = variables.getScopeAtIndex(3); + let globalScope = variables.getScopeAtIndex(4); ok(firstScope, "The first scope is available."); ok(secondScope, "The second scope is available."); ok(thirdScope, "The third scope is available."); + ok(globalLexicalScope, "The global lexical scope is available."); ok(globalScope, "The global scope is available."); is(firstScope.name, "Function scope [secondNest]", @@ -34,6 +36,8 @@ function test() { "The second scope's name is correct."); is(thirdScope.name, "Function scope [test]", "The third scope's name is correct."); + is(globalLexicalScope.name, "Block scope", + "The global lexical scope's name is correct."); is(globalScope.name, "Global scope [Window]", "The global scope's name is correct."); @@ -43,6 +47,8 @@ function test() { "The second scope's expansion state is correct."); is(thirdScope.expanded, false, "The third scope's expansion state is correct."); + is(globalLexicalScope.expanded, false, + "The global lexical scope's expansion state is correct."); is(globalScope.expanded, false, "The global scope's expansion state is correct."); @@ -52,6 +58,8 @@ function test() { "The second scope should have no variables available yet."); is(thirdScope._store.size, 0, "The third scope should have no variables available yet."); + is(globalLexicalScope._store.size, 0, + "The global scope should have no variables available yet."); is(globalScope._store.size, 0, "The global scope should have no variables available yet."); @@ -100,6 +108,7 @@ function test() { fetched = waitForDebuggerEvents(panel, events.FETCHED_VARIABLES); secondScope.expand(); thirdScope.expand(); + globalLexicalScope.expand(); globalScope.expand(); yield fetched; diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-16.js b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-16.js index 4b4e0407e1e0..676878d245cd 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-16.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-16.js @@ -42,7 +42,7 @@ function test() { } function expandGlobalScope() { - let globalScope = variables.getScopeAtIndex(1); + let globalScope = variables.getScopeAtIndex(2); is(globalScope.expanded, false, "The globalScope should not be expanded yet."); diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-reexpand-01.js b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-reexpand-01.js index 5beab91342af..70a638e85e50 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-reexpand-01.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-reexpand-01.js @@ -74,7 +74,8 @@ function testVariablesExpand() { let localScope = gVariables.getScopeAtIndex(0); let withScope = gVariables.getScopeAtIndex(1); let functionScope = gVariables.getScopeAtIndex(2); - let globalScope = gVariables.getScopeAtIndex(3); + let globalLexicalScope = gVariables.getScopeAtIndex(3); + let globalScope = gVariables.getScopeAtIndex(4); let thisVar = localScope.get("this"); let windowVar = thisVar.get("window"); @@ -85,6 +86,8 @@ function testVariablesExpand() { "The withScope arrow should still be expanded."); is(functionScope.target.querySelector(".arrow").hasAttribute("open"), true, "The functionScope arrow should still be expanded."); + is(globalLexicalScope.target.querySelector(".arrow").hasAttribute("open"), true, + "The globalLexicalScope arrow should still be expanded."); is(globalScope.target.querySelector(".arrow").hasAttribute("open"), true, "The globalScope arrow should still be expanded."); is(thisVar.target.querySelector(".arrow").hasAttribute("open"), true, @@ -98,6 +101,8 @@ function testVariablesExpand() { "The withScope enumerables should still be expanded."); is(functionScope.target.querySelector(".variables-view-element-details").hasAttribute("open"), true, "The functionScope enumerables should still be expanded."); + is(globalLexicalScope.target.querySelector(".variables-view-element-details").hasAttribute("open"), true, + "The globalLexicalScope enumerables should still be expanded."); is(globalScope.target.querySelector(".variables-view-element-details").hasAttribute("open"), true, "The globalScope enumerables should still be expanded."); is(thisVar.target.querySelector(".variables-view-element-details").hasAttribute("open"), true, @@ -111,6 +116,8 @@ function testVariablesExpand() { "The withScope expanded getter should return true."); is(functionScope.expanded, true, "The functionScope expanded getter should return true."); + is(globalLexicalScope.expanded, true, + "The globalScope expanded getter should return true."); is(globalScope.expanded, true, "The globalScope expanded getter should return true."); is(thisVar.expanded, true, @@ -125,7 +132,8 @@ function prepareVariablesAndProperties() { let localScope = gVariables.getScopeAtIndex(0); let withScope = gVariables.getScopeAtIndex(1); let functionScope = gVariables.getScopeAtIndex(2); - let globalScope = gVariables.getScopeAtIndex(3); + let globalLexicalScope = gVariables.getScopeAtIndex(3); + let globalScope = gVariables.getScopeAtIndex(4); is(localScope.expanded, true, "The localScope should be expanded."); @@ -133,6 +141,8 @@ function prepareVariablesAndProperties() { "The withScope should not be expanded yet."); is(functionScope.expanded, false, "The functionScope should not be expanded yet."); + is(globalLexicalScope.expanded, false, + "The globalLexicalScope should not be expanded yet."); is(globalScope.expanded, false, "The globalScope should not be expanded yet."); @@ -145,6 +155,8 @@ function prepareVariablesAndProperties() { "The withScope should now be expanded."); is(functionScope.expanded, true, "The functionScope should now be expanded."); + is(globalLexicalScope.expanded, true, + "The globalLexicalScope should now be expanded."); is(globalScope.expanded, true, "The globalScope should now be expanded."); @@ -186,6 +198,7 @@ function prepareVariablesAndProperties() { withScope.expand(); functionScope.expand(); + globalLexicalScope.expand(); globalScope.expand(); return deferred.promise; diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-reexpand-02.js b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-reexpand-02.js index 67e0abe843ce..4da9046db63d 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-reexpand-02.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-reexpand-02.js @@ -75,7 +75,8 @@ function testVariablesExpand() { let localScope = gVariables.getScopeAtIndex(0); let withScope = gVariables.getScopeAtIndex(1); let functionScope = gVariables.getScopeAtIndex(2); - let globalScope = gVariables.getScopeAtIndex(3); + let globalLexicalScope = gVariables.getScopeAtIndex(3); + let globalScope = gVariables.getScopeAtIndex(4); let thisVar = localScope.get("this"); let windowVar = thisVar.get("window"); @@ -88,6 +89,8 @@ function testVariablesExpand() { "The withScope arrow should still be expanded."); is(functionScope.target.querySelector(".arrow").hasAttribute("open"), true, "The functionScope arrow should still be expanded."); + is(globalLexicalScope.target.querySelector(".arrow").hasAttribute("open"), true, + "The globalLexicalScope arrow should still be expanded."); is(globalScope.target.querySelector(".arrow").hasAttribute("open"), true, "The globalScope arrow should still be expanded."); is(thisVar.target.querySelector(".arrow").hasAttribute("open"), true, @@ -105,6 +108,8 @@ function testVariablesExpand() { "The withScope enumerables should still be expanded."); is(functionScope.target.querySelector(".variables-view-element-details").hasAttribute("open"), true, "The functionScope enumerables should still be expanded."); + is(globalLexicalScope.target.querySelector(".variables-view-element-details").hasAttribute("open"), true, + "The globalLexicalScope enumerables should still be expanded."); is(globalScope.target.querySelector(".variables-view-element-details").hasAttribute("open"), true, "The globalScope enumerables should still be expanded."); is(thisVar.target.querySelector(".variables-view-element-details").hasAttribute("open"), true, @@ -122,6 +127,8 @@ function testVariablesExpand() { "The withScope expanded getter should return true."); is(functionScope.expanded, true, "The functionScope expanded getter should return true."); + is(globalLexicalScope.expanded, true, + "The globalLexicalScope expanded getter should return true."); is(globalScope.expanded, true, "The globalScope expanded getter should return true."); is(thisVar.expanded, true, @@ -140,7 +147,8 @@ function prepareVariablesAndProperties() { let localScope = gVariables.getScopeAtIndex(0); let withScope = gVariables.getScopeAtIndex(1); let functionScope = gVariables.getScopeAtIndex(2); - let globalScope = gVariables.getScopeAtIndex(3); + let globalLexicalScope = gVariables.getScopeAtIndex(3); + let globalScope = gVariables.getScopeAtIndex(4); is(localScope.expanded, true, "The localScope should be expanded."); @@ -148,6 +156,8 @@ function prepareVariablesAndProperties() { "The withScope should not be expanded yet."); is(functionScope.expanded, false, "The functionScope should not be expanded yet."); + is(globalLexicalScope.expanded, false, + "The globalLexicalScope should not be expanded yet."); is(globalScope.expanded, false, "The globalScope should not be expanded yet."); @@ -160,6 +170,8 @@ function prepareVariablesAndProperties() { "The withScope should now be expanded."); is(functionScope.expanded, true, "The functionScope should now be expanded."); + is(globalLexicalScope.expanded, true, + "The globalLexicalScope should now be expanded."); is(globalScope.expanded, true, "The globalScope should now be expanded."); @@ -201,6 +213,7 @@ function prepareVariablesAndProperties() { withScope.expand(); functionScope.expand(); + globalLexicalScope.expand(); globalScope.expand(); return deferred.promise; diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-webidl.js b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-webidl.js index 4988755bf1b4..f21c78e41c11 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-webidl.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-webidl.js @@ -36,7 +36,7 @@ function test() { function expandGlobalScope() { let deferred = promise.defer(); - let globalScope = gVariables.getScopeAtIndex(1); + let globalScope = gVariables.getScopeAtIndex(2); is(globalScope.expanded, false, "The global scope should not be expanded by default."); @@ -51,7 +51,7 @@ function expandGlobalScope() { function performTest() { let deferred = promise.defer(); - let globalScope = gVariables.getScopeAtIndex(1); + let globalScope = gVariables.getScopeAtIndex(2); let buttonVar = globalScope.get("button"); let buttonAsProtoVar = globalScope.get("buttonAsProto"); diff --git a/devtools/client/debugger/test/mochitest/doc_function-search.html b/devtools/client/debugger/test/mochitest/doc_function-search.html index 711a873edb73..eb0e7eaeae9d 100644 --- a/devtools/client/debugger/test/mochitest/doc_function-search.html +++ b/devtools/client/debugger/test/mochitest/doc_function-search.html @@ -17,10 +17,10 @@ diff --git a/toolkit/components/aboutmemory/tests/test_aboutmemory.xul b/toolkit/components/aboutmemory/tests/test_aboutmemory.xul index bfeab4c7b415..d00e1ae1538b 100644 --- a/toolkit/components/aboutmemory/tests/test_aboutmemory.xul +++ b/toolkit/components/aboutmemory/tests/test_aboutmemory.xul @@ -119,6 +119,21 @@ mgr.registerStrongReporterEvenIfBlocked(fakeReporters[i]); } + // mgr.explicit sums "heap-allocated" and all the appropriate NONHEAP ones: + // - "explicit/c", "explicit/cc" x 2, "explicit/d", "explicit/e" + // - but *not* "explicit/c/d" x 2 + // Check explicit now before we add the fake reporters for the fake 2nd + // and subsequent processes. + // + // Nb: mgr.explicit will throw NS_ERROR_NOT_AVAILABLE if this is a + // --disable-jemalloc build. Allow for that exception, but *only* that + // exception. + try { + is(mgr.explicit, 500*MB + (100 + 13 + 10)*MB + 599*KB, "mgr.explicit"); + } catch (ex) { + is(ex.result, Cr.NS_ERROR_NOT_AVAILABLE, "mgr.explicit exception"); + } + // The main process always comes first when we display about:memory. The // remaining processes are sorted by their |resident| values (starting with // the largest). Processes without a |resident| memory reporter are saved @@ -552,14 +567,7 @@ End of 5th\n\ SimpleTest.waitForClipboard( function(aActual) { mostRecentActual = aActual; - let rslt = aActual.trim() === aExpected.trim(); - if (!rslt) { - // Try copying again. - synthesizeKey("A", {accelKey: true}); - synthesizeKey("C", {accelKey: true}); - } - - return rslt; + return aActual.trim() === aExpected.trim(); }, function() { synthesizeKey("A", {accelKey: true}); diff --git a/toolkit/components/aboutmemory/tests/test_aboutmemory2.xul b/toolkit/components/aboutmemory/tests/test_aboutmemory2.xul index 8cf197e6d114..e2f93d0adc4a 100644 --- a/toolkit/components/aboutmemory/tests/test_aboutmemory2.xul +++ b/toolkit/components/aboutmemory/tests/test_aboutmemory2.xul @@ -106,14 +106,7 @@ SimpleTest.waitForClipboard( function(aActual) { mostRecentActual = aActual; - let rslt = aActual.trim() === aExpected.trim(); - if (!rslt) { - // Try copying again. - synthesizeKey("A", {accelKey: true}); - synthesizeKey("C", {accelKey: true}); - } - - return rslt; + return aActual.trim() === aExpected.trim(); }, function() { synthesizeKey("A", {accelKey: true}); diff --git a/toolkit/components/aboutmemory/tests/test_memoryReporters.xul b/toolkit/components/aboutmemory/tests/test_memoryReporters.xul index 035bb05ed48e..d9f1b81064e3 100644 --- a/toolkit/components/aboutmemory/tests/test_memoryReporters.xul +++ b/toolkit/components/aboutmemory/tests/test_memoryReporters.xul @@ -44,8 +44,6 @@ const XUL_NS = "http:\\\\www.mozilla.org\\keymaster\\gatekeeper\\there.is.only.xul"; - SimpleTest.waitForExplicitFinish(); - let vsizeAmounts = []; let residentAmounts = []; let heapAllocatedAmounts = []; @@ -143,6 +141,21 @@ let mgr = Cc["@mozilla.org/memory-reporter-manager;1"]. getService(Ci.nsIMemoryReporterManager); + // Access the distinguished amounts (mgr.explicit et al.) just to make sure + // they don't crash. We can't check their actual values because they're + // non-deterministic. + // + // Nb: mgr.explicit will throw NS_ERROR_NOT_AVAILABLE if this is a + // --disable-jemalloc build. Allow for that exception, but *only* that + // exception. + let dummy; + let haveExplicit = true; + try { + dummy = mgr.explicit; + } catch (ex) { + is(ex.result, Cr.NS_ERROR_NOT_AVAILABLE, "mgr.explicit exception"); + haveExplicit = false; + } let amounts = [ "vsize", "vsizeMaxContiguous", @@ -169,7 +182,7 @@ // aren't available on all platforms. But if the attribute simply // isn't present, that indicates the distinguished amounts have changed // and this file hasn't been updated appropriately. - let dummy = mgr[amounts[i]]; + dummy = mgr[amounts[i]]; ok(dummy !== undefined, "accessed an unknown distinguished amount: " + amounts[i]); } catch (ex) { @@ -191,33 +204,11 @@ domSize, styleSize, otherSize, totalSize, jsMilliseconds, nonJSMilliseconds); - let asyncSteps = [ - getReportsNormal, - getReportsAnonymized, - checkResults, - test_register_strong, - test_register_strong, // Make sure re-registering works - test_register_weak, - SimpleTest.finish - ]; + mgr.getReportsForThisProcess(handleReportNormal, null, + /* anonymize = */ false); - function runNext() { - setTimeout(asyncSteps.shift(), 0); - } - - function getReportsNormal() - { - mgr.getReports(handleReportNormal, null, - runNext, null, - /* anonymize = */ false); - } - - function getReportsAnonymized() - { - mgr.getReports(handleReportAnonymized, null, - runNext, null, - /* anonymize = */ true); - } + mgr.getReportsForThisProcess(handleReportAnonymized, null, + /* anonymize = */ true); function checkSizeReasonable(aName, aAmount) { @@ -235,50 +226,40 @@ } } - function checkResults() - { - try { - // Nb: mgr.heapAllocated will throw NS_ERROR_NOT_AVAILABLE if this is a - // --disable-jemalloc build. Allow for skipping this test on that - // exception, but *only* that exception. - let dummy = mgr.heapAllocated; - checkSpecialReport("heap-allocated", heapAllocatedAmounts); - } catch (ex) { - is(ex.result, Cr.NS_ERROR_NOT_AVAILABLE, "mgr.heapAllocated exception"); - } - // vsize may be unreasonable if ASAN is enabled - checkSpecialReport("vsize", vsizeAmounts, /*canBeUnreasonable*/true); - checkSpecialReport("resident", residentAmounts); - - for (var reporter in jsGcHeapUsedGcThings) { - ok(jsGcHeapUsedGcThings[reporter] == 1); - } - checkSizeReasonable("js-main-runtime-gc-heap-committed/used/gc-things", - jsGcHeapUsedGcThingsTotal); - - ok(present.jsNonWindowCompartments, "js-non-window compartments are present"); - ok(present.windowObjectsJsCompartments, "window-objects/.../js compartments are present"); - ok(present.places, "places is present"); - ok(present.images, "images is present"); - ok(present.xptiWorkingSet, "xpti-working-set is present"); - ok(present.atomTablesMain, "atom-tables/main is present"); - ok(present.sandboxLocation, "sandbox locations are present"); - ok(present.bigString, "large string is present"); - ok(present.smallString1, "small string 1 is present"); - ok(present.smallString2, "small string 2 is present"); - - ok(!present.anonymizedWhenUnnecessary, - "anonymized paths are not present when unnecessary. Failed case: " + - present.anonymizedWhenUnnecessary); - ok(!present.httpWhenAnonymized, - "http URLs are anonymized when necessary. Failed case: " + - present.httpWhenAnonymized); - ok(!present.unanonymizedFilePathWhenAnonymized, - "file URLs are anonymized when necessary. Failed case: " + - present.unanonymizedFilePathWhenAnonymized); - - runNext(); + // If mgr.explicit failed, we won't have "heap-allocated" either. + if (haveExplicit) { + checkSpecialReport("heap-allocated", heapAllocatedAmounts); } + // vsize may be unreasonable if ASAN is enabled + checkSpecialReport("vsize", vsizeAmounts, /*canBeUnreasonable*/true); + checkSpecialReport("resident", residentAmounts); + + for (var reporter in jsGcHeapUsedGcThings) { + ok(jsGcHeapUsedGcThings[reporter] == 1); + } + checkSizeReasonable("js-main-runtime-gc-heap-committed/used/gc-things", + jsGcHeapUsedGcThingsTotal); + + ok(present.jsNonWindowCompartments, "js-non-window compartments are present"); + ok(present.windowObjectsJsCompartments, "window-objects/.../js compartments are present"); + ok(present.places, "places is present"); + ok(present.images, "images is present"); + ok(present.xptiWorkingSet, "xpti-working-set is present"); + ok(present.atomTablesMain, "atom-tables/main is present"); + ok(present.sandboxLocation, "sandbox locations are present"); + ok(present.bigString, "large string is present"); + ok(present.smallString1, "small string 1 is present"); + ok(present.smallString2, "small string 2 is present"); + + ok(!present.anonymizedWhenUnnecessary, + "anonymized paths are not present when unnecessary. Failed case: " + + present.anonymizedWhenUnnecessary); + ok(!present.httpWhenAnonymized, + "http URLs are anonymized when necessary. Failed case: " + + present.httpWhenAnonymized); + ok(!present.unanonymizedFilePathWhenAnonymized, + "file URLs are anonymized when necessary. Failed case: " + + present.unanonymizedFilePathWhenAnonymized); // Reporter registration tests @@ -371,28 +352,27 @@ mgr.registerStrongReporter(reporterAndCallback); // Check the generated reports. - mgr.getReports(reporterAndCallback, null, - () => { - reporterAndCallback.finish(); - window.setTimeout(test_unregister_strong, 0, reporterAndCallback); - }, null, - /* anonymize = */ false); - } + mgr.getReportsForThisProcess(reporterAndCallback, null, + /* anonymize = */ false); + reporterAndCallback.finish(); - function test_unregister_strong(aReporterAndCallback) - { - mgr.unregisterStrongReporter(aReporterAndCallback); + // Unregistration works. + mgr.unregisterStrongReporter(reporterAndCallback); // The reporter was unregistered, hence there shouldn't be any reports from // the test reporter. - mgr.getReports(aReporterAndCallback, null, - () => { - aReporterAndCallback.finish(0); - runNext(); - }, null, - /* anonymize = */ false); + mgr.getReportsForThisProcess(reporterAndCallback, null, + /* anonymize = */ false); + reporterAndCallback.finish(0); } + test_register_strong(); + + // Check strong reporters a second time, to make sure a reporter can be + // re-registered. + test_register_strong(); + + // Check that you cannot register JS components as weak reporters. function test_register_weak() { let reporterAndCallback = new MemoryReporterAndCallback(); @@ -412,12 +392,9 @@ ok(ex.message.indexOf("NS_ERROR_") >= 0, "WrappedJS reporter got rejected: " + ex); } - - runNext(); } - // Kick-off the async tests. - runNext(); + test_register_weak(); ]]> diff --git a/toolkit/components/aboutmemory/tests/test_sqliteMultiReporter.xul b/toolkit/components/aboutmemory/tests/test_sqliteMultiReporter.xul index 3452bbbc7205..29c85a5c72a8 100644 --- a/toolkit/components/aboutmemory/tests/test_sqliteMultiReporter.xul +++ b/toolkit/components/aboutmemory/tests/test_sqliteMultiReporter.xul @@ -24,8 +24,6 @@ const Ci = Components.interfaces; const Cu = Components.utils; - SimpleTest.waitForExplicitFinish(); - // Make a fake DB file. let file = Cc["@mozilla.org/file/directory_service;1"]. getService(Ci.nsIProperties). @@ -42,12 +40,11 @@ // them. It shouldn't crash. let mgr = Cc["@mozilla.org/memory-reporter-manager;1"]. getService(Ci.nsIMemoryReporterManager); - mgr.getReports(function(){}, null, - () => { - ok(true, "didn't crash"); - SimpleTest.finish(); - }, null, - /* anonymize = */ false); + mgr.getReportsForThisProcess(function(){}, null, /* anonymize = */ false); + + // If we haven't crashed, we've passed, but the test harness requires that + // we explicitly check something. + ok(true, "didn't crash"); ]]> diff --git a/xpcom/base/nsIMemoryReporter.idl b/xpcom/base/nsIMemoryReporter.idl index e00f736f55c9..39e3be823b18 100644 --- a/xpcom/base/nsIMemoryReporter.idl +++ b/xpcom/base/nsIMemoryReporter.idl @@ -205,7 +205,7 @@ interface nsIFinishReportingCallback : nsISupports void callback(in nsISupports data); }; -[scriptable, builtinclass, uuid(61de6dc7-ed11-4104-a577-79941f22f434)] +[scriptable, builtinclass, uuid(5e4eaa5a-4808-4b97-8005-e7cdc4d73693)] interface nsIMemoryReporterManager : nsISupports { /* @@ -220,7 +220,6 @@ interface nsIMemoryReporterManager : nsISupports * unregisterStrongReporter() at any point. */ void registerStrongReporter(in nsIMemoryReporter reporter); - void registerStrongAsyncReporter(in nsIMemoryReporter reporter); /* * Like registerReporter, but the Manager service will hold a weak reference @@ -230,7 +229,6 @@ interface nsIMemoryReporterManager : nsISupports * register your JavaScript components with registerStrongReporter(). */ void registerWeakReporter(in nsIMemoryReporter reporter); - void registerWeakAsyncReporter(in nsIMemoryReporter reporter); /* * Unregister the given memory reporter, which must have been registered with @@ -291,6 +289,14 @@ interface nsIMemoryReporterManager : nsISupports in boolean minimizeMemoryUsage, in AString DMDDumpIdent); + /* + * Get memory reports in the current process only. |handleReport| is called + * for each report. + */ + void getReportsForThisProcess(in nsIMemoryReporterCallback handleReport, + in nsISupports handleReportData, + in boolean anonymize); + /* * As above, but if DMD is enabled and |DMDFile| is non-null then * write a DMD report to that file and close it. @@ -299,14 +305,7 @@ interface nsIMemoryReporterManager : nsISupports getReportsForThisProcessExtended(in nsIMemoryReporterCallback handleReport, in nsISupports handleReportData, in boolean anonymize, - in FILE DMDFile, - in nsIFinishReportingCallback finishReporting, - in nsISupports finishReportingData); - - /* - * Called by an asynchronous memory reporter upon completion. - */ - [noscript] void endReport(); + in FILE DMDFile); /* * The memory reporter manager, for the most part, treats reporters @@ -316,8 +315,9 @@ interface nsIMemoryReporterManager : nsISupports * interesting that we want external code (e.g. telemetry) to be able to rely * on them. * - * Note that these are not reporters and so getReports() does not look at - * them. However, distinguished amounts can be embedded in a reporter. + * Note that these are not reporters and so getReports() and + * getReportsForThisProcess() do not look at them. However, distinguished + * amounts can be embedded in a reporter. * * Access to these attributes can fail. In particular, some of them are not * available on all platforms. @@ -325,6 +325,11 @@ interface nsIMemoryReporterManager : nsISupports * If you add a new distinguished amount, please update * toolkit/components/aboutmemory/tests/test_memoryReporters.xul. * + * |explicit| (UNITS_BYTES) The total size of explicit memory allocations, + * both at the OS-level (eg. via mmap, VirtualAlloc) and at the heap level + * (eg. via malloc, calloc, operator new). It covers all heap allocations, + * but will miss any OS-level ones not covered by memory reporters. + * * |vsize| (UNITS_BYTES) The virtual size, i.e. the amount of address space * taken up. * @@ -373,6 +378,7 @@ interface nsIMemoryReporterManager : nsISupports * |pageFaultsHard| (UNITS_COUNT_CUMULATIVE) The number of hard (a.k.a. * major) page faults that have occurred since the process started. */ + readonly attribute int64_t explicit; readonly attribute int64_t vsize; readonly attribute int64_t vsizeMaxContiguous; readonly attribute int64_t resident; @@ -453,12 +459,10 @@ namespace mozilla { // Register a memory reporter. The manager service will hold a strong // reference to this reporter. XPCOM_API(nsresult) RegisterStrongMemoryReporter(nsIMemoryReporter* aReporter); -XPCOM_API(nsresult) RegisterStrongAsyncMemoryReporter(nsIMemoryReporter* aReporter); // Register a memory reporter. The manager service will hold a weak reference // to this reporter. XPCOM_API(nsresult) RegisterWeakMemoryReporter(nsIMemoryReporter* aReporter); -XPCOM_API(nsresult) RegisterWeakAsyncMemoryReporter(nsIMemoryReporter* aReporter); // Unregister a strong memory reporter. XPCOM_API(nsresult) UnregisterStrongMemoryReporter(nsIMemoryReporter* aReporter); @@ -516,6 +520,15 @@ nsresult RegisterNonJSSizeOfTab(NonJSSizeOfTabFn aSizeOfTabFn); } #if defined(MOZ_DMD) && !defined(MOZILLA_XPCOMRT_API) +namespace mozilla { +namespace dmd { +// This runs all the memory reporters in the current process but does nothing +// with the results; i.e. it does the minimal amount of work possible for DMD +// to do its thing. It does nothing with child processes. +void RunReportersForThisProcess(); +} +} + #if !defined(MOZ_MEMORY) #error "MOZ_DMD requires MOZ_MEMORY" #endif diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp index eef9f403a595..4deb78839699 100644 --- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -1356,8 +1356,7 @@ nsMemoryReporterManager::nsMemoryReporterManager() , mSavedStrongReporters(nullptr) , mSavedWeakReporters(nullptr) , mNextGeneration(1) - , mPendingProcessesState(nullptr) - , mPendingReportersState(nullptr) + , mGetReportsState(nullptr) { } @@ -1415,11 +1414,11 @@ nsMemoryReporterManager::GetReportsExtended( uint32_t generation = mNextGeneration++; - if (mPendingProcessesState) { + if (mGetReportsState) { // A request is in flight. Don't start another one. And don't report // an error; just ignore it, and let the in-flight request finish. MEMORY_REPORTING_LOG("GetReports (gen=%u, s->gen=%u): abort\n", - generation, mPendingProcessesState->mGeneration); + generation, mGetReportsState->mGeneration); return NS_OK; } @@ -1430,15 +1429,16 @@ nsMemoryReporterManager::GetReportsExtended( if (concurrency < 1) { concurrency = 1; } - mPendingProcessesState = new PendingProcessesState(generation, - aAnonymize, - aMinimize, - concurrency, - aHandleReport, - aHandleReportData, - aFinishReporting, - aFinishReportingData, - aDMDDumpIdent); + mGetReportsState = new GetReportsState(generation, + aAnonymize, + aMinimize, + concurrency, + aHandleReport, + aHandleReportData, + aFinishReporting, + aFinishReportingData, + aDMDDumpIdent); + mGetReportsState->mChildrenPending = new nsTArray>(); if (aMinimize) { rv = MinimizeMemoryUsage(NS_NewRunnableMethod( @@ -1452,7 +1452,7 @@ nsMemoryReporterManager::GetReportsExtended( nsresult nsMemoryReporterManager::StartGettingReports() { - PendingProcessesState* s = mPendingProcessesState; + GetReportsState* s = mGetReportsState; nsresult rv; // Get reports for this process. @@ -1467,11 +1467,8 @@ nsMemoryReporterManager::StartGettingReports() } } #endif - - // This is async. GetReportsForThisProcessExtended(s->mHandleReport, s->mHandleReportData, - s->mAnonymize, parentDMDFile, - s->mFinishReporting, s->mFinishReportingData); + s->mAnonymize, parentDMDFile); nsTArray childWeakRefs; ContentParent::GetAll(childWeakRefs); @@ -1482,7 +1479,7 @@ nsMemoryReporterManager::StartGettingReports() // to be buffered and consume (possibly scarce) memory. for (size_t i = 0; i < childWeakRefs.Length(); ++i) { - s->mChildrenPending.AppendElement(childWeakRefs[i]); + s->mChildrenPending->AppendElement(childWeakRefs[i]); } nsCOMPtr timer = do_CreateInstance(NS_TIMER_CONTRACTID); @@ -1503,44 +1500,25 @@ nsMemoryReporterManager::StartGettingReports() s->mTimer.swap(timer); } + // The parent's report is done; make note of that, and start + // launching child process reports (if any). + EndProcessReport(s->mGeneration, true); return NS_OK; } -void -nsMemoryReporterManager::DispatchReporter( - nsIMemoryReporter* aReporter, bool aIsAsync, +NS_IMETHODIMP +nsMemoryReporterManager::GetReportsForThisProcess( nsIHandleReportCallback* aHandleReport, - nsISupports* aHandleReportData, - bool aAnonymize) + nsISupports* aHandleReportData, bool aAnonymize) { - MOZ_ASSERT(mPendingReportersState); - - // Grab refs to everything used in the lambda function. - nsRefPtr self = this; - nsCOMPtr reporter = aReporter; - nsCOMPtr handleReport = aHandleReport; - nsCOMPtr handleReportData = aHandleReportData; - - nsCOMPtr event = NS_NewRunnableFunction( - [self, reporter, aIsAsync, handleReport, handleReportData, aAnonymize] () { - reporter->CollectReports(handleReport, - handleReportData, - aAnonymize); - if (!aIsAsync) { - self->EndReport(); - } - }); - - NS_DispatchToMainThread(event); - mPendingReportersState->mReportsPending++; + return GetReportsForThisProcessExtended(aHandleReport, aHandleReportData, + aAnonymize, nullptr); } NS_IMETHODIMP nsMemoryReporterManager::GetReportsForThisProcessExtended( nsIHandleReportCallback* aHandleReport, nsISupports* aHandleReportData, - bool aAnonymize, FILE* aDMDFile, - nsIFinishReportingCallback* aFinishReporting, - nsISupports* aFinishReportingData) + bool aAnonymize, FILE* aDMDFile) { // Memory reporters are not necessarily threadsafe, so this function must // be called from the main thread. @@ -1548,11 +1526,6 @@ nsMemoryReporterManager::GetReportsForThisProcessExtended( MOZ_CRASH(); } - if (NS_WARN_IF(mPendingReportersState)) { - // Report is already in progress. - return NS_ERROR_IN_PROGRESS; - } - #ifdef MOZ_DMD if (aDMDFile) { // Clear DMD's reportedness state before running the memory @@ -1563,58 +1536,39 @@ nsMemoryReporterManager::GetReportsForThisProcessExtended( MOZ_ASSERT(!aDMDFile); #endif - mPendingReportersState = new PendingReportersState( - aFinishReporting, aFinishReportingData, aDMDFile); - + nsCOMArray allReporters; { mozilla::MutexAutoLock autoLock(mMutex); - for (auto iter = mStrongReporters->Iter(); !iter.Done(); iter.Next()) { - DispatchReporter(iter.Key(), iter.Data(), - aHandleReport, aHandleReportData, aAnonymize); + nsRefPtrHashKey* entry = iter.Get(); + allReporters.AppendElement(entry->GetKey()); } - for (auto iter = mWeakReporters->Iter(); !iter.Done(); iter.Next()) { - nsCOMPtr reporter = iter.Key(); - DispatchReporter(reporter, iter.Data(), - aHandleReport, aHandleReportData, aAnonymize); + nsPtrHashKey* entry = iter.Get(); + allReporters.AppendElement(entry->GetKey()); } } + for (uint32_t i = 0; i < allReporters.Length(); i++) { + allReporters[i]->CollectReports(aHandleReport, aHandleReportData, + aAnonymize); + } - return NS_OK; -} - -NS_IMETHODIMP -nsMemoryReporterManager::EndReport() -{ - if (--mPendingReportersState->mReportsPending == 0) { #ifdef MOZ_DMD - if (mPendingReportersState->mDMDFile) { - nsMemoryInfoDumper::DumpDMDToFile(mPendingReportersState->mDMDFile); - } -#endif - if (mPendingProcessesState) { - // This is the parent process. - EndProcessReport(mPendingProcessesState->mGeneration, true); - } else { - mPendingReportersState->mFinishReporting->Callback( - mPendingReportersState->mFinishReportingData); - } - - delete mPendingReportersState; - mPendingReportersState = nullptr; + if (aDMDFile) { + return nsMemoryInfoDumper::DumpDMDToFile(aDMDFile); } +#endif return NS_OK; } -nsMemoryReporterManager::PendingProcessesState* +nsMemoryReporterManager::GetReportsState* nsMemoryReporterManager::GetStateForGeneration(uint32_t aGeneration) { // Memory reporting only happens on the main thread. MOZ_RELEASE_ASSERT(NS_IsMainThread()); - PendingProcessesState* s = mPendingProcessesState; + GetReportsState* s = mGetReportsState; if (!s) { // If we reach here, then: @@ -1651,7 +1605,7 @@ nsMemoryReporterManager::HandleChildReport( uint32_t aGeneration, const dom::MemoryReport& aChildReport) { - PendingProcessesState* s = GetStateForGeneration(aGeneration); + GetReportsState* s = GetStateForGeneration(aGeneration); if (!s) { return; } @@ -1671,7 +1625,7 @@ nsMemoryReporterManager::HandleChildReport( /* static */ bool nsMemoryReporterManager::StartChildReport(mozilla::dom::ContentParent* aChild, - const PendingProcessesState* aState) + const GetReportsState* aState) { #ifdef MOZ_NUWA_PROCESS if (aChild->IsNuwaProcess()) { @@ -1709,7 +1663,7 @@ nsMemoryReporterManager::StartChildReport(mozilla::dom::ContentParent* aChild, void nsMemoryReporterManager::EndProcessReport(uint32_t aGeneration, bool aSuccess) { - PendingProcessesState* s = GetStateForGeneration(aGeneration); + GetReportsState* s = GetStateForGeneration(aGeneration); if (!s) { return; } @@ -1722,29 +1676,29 @@ nsMemoryReporterManager::EndProcessReport(uint32_t aGeneration, bool aSuccess) aGeneration, s->mNumProcessesCompleted, aSuccess ? "completed" : "exited during report", s->mNumProcessesRunning, - static_cast(s->mChildrenPending.Length())); + static_cast(s->mChildrenPending->Length())); // Start pending children up to the concurrency limit. while (s->mNumProcessesRunning < s->mConcurrencyLimit && - !s->mChildrenPending.IsEmpty()) { + !s->mChildrenPending->IsEmpty()) { // Pop last element from s->mChildrenPending nsRefPtr nextChild; - nextChild.swap(s->mChildrenPending.LastElement()); - s->mChildrenPending.TruncateLength(s->mChildrenPending.Length() - 1); + nextChild.swap(s->mChildrenPending->LastElement()); + s->mChildrenPending->TruncateLength(s->mChildrenPending->Length() - 1); // Start report (if the child is still alive and not Nuwa). if (StartChildReport(nextChild, s)) { ++s->mNumProcessesRunning; MEMORY_REPORTING_LOG("HandleChildReports (aGen=%u): started child report" " (%u running, %u pending)\n", aGeneration, s->mNumProcessesRunning, - static_cast(s->mChildrenPending.Length())); + static_cast(s->mChildrenPending->Length())); } } // If all the child processes (if any) have reported, we can cancel // the timer (if started) and finish up. Otherwise, just return. if (s->mNumProcessesRunning == 0) { - MOZ_ASSERT(s->mChildrenPending.IsEmpty()); + MOZ_ASSERT(s->mChildrenPending->IsEmpty()); if (s->mTimer) { s->mTimer->Cancel(); } @@ -1756,15 +1710,15 @@ nsMemoryReporterManager::EndProcessReport(uint32_t aGeneration, bool aSuccess) nsMemoryReporterManager::TimeoutCallback(nsITimer* aTimer, void* aData) { nsMemoryReporterManager* mgr = static_cast(aData); - PendingProcessesState* s = mgr->mPendingProcessesState; + GetReportsState* s = mgr->mGetReportsState; // Release assert because: if the pointer is null we're about to // crash regardless of DEBUG, and this way the compiler doesn't // complain about unused variables. - MOZ_RELEASE_ASSERT(s, "mgr->mPendingProcessesState"); + MOZ_RELEASE_ASSERT(s, "mgr->mGetReportsState"); MEMORY_REPORTING_LOG("TimeoutCallback (s->gen=%u; %u running, %u pending)\n", s->mGeneration, s->mNumProcessesRunning, - static_cast(s->mChildrenPending.Length())); + static_cast(s->mChildrenPending->Length())); // We don't bother sending any kind of cancellation message to the child // processes that haven't reported back. @@ -1779,43 +1733,25 @@ nsMemoryReporterManager::FinishReporting() MOZ_CRASH(); } - MOZ_ASSERT(mPendingProcessesState); + MOZ_ASSERT(mGetReportsState); MEMORY_REPORTING_LOG("FinishReporting (s->gen=%u; %u processes reported)\n", - mPendingProcessesState->mGeneration, - mPendingProcessesState->mNumProcessesCompleted); + mGetReportsState->mGeneration, + mGetReportsState->mNumProcessesCompleted); - // Call this before deleting |mPendingProcessesState|. That way, if + // Call this before deleting |mGetReportsState|. That way, if // |mFinishReportData| calls GetReports(), it will silently abort, as // required. - nsresult rv = mPendingProcessesState->mFinishReporting->Callback( - mPendingProcessesState->mFinishReportingData); + nsresult rv = mGetReportsState->mFinishReporting->Callback( + mGetReportsState->mFinishReportingData); - delete mPendingProcessesState; - mPendingProcessesState = nullptr; + delete mGetReportsState; + mGetReportsState = nullptr; return rv; } -nsMemoryReporterManager::PendingProcessesState::PendingProcessesState( - uint32_t aGeneration, bool aAnonymize, bool aMinimize, - uint32_t aConcurrencyLimit, - nsIHandleReportCallback* aHandleReport, - nsISupports* aHandleReportData, - nsIFinishReportingCallback* aFinishReporting, - nsISupports* aFinishReportingData, - const nsAString& aDMDDumpIdent) - : mGeneration(aGeneration) - , mAnonymize(aAnonymize) - , mMinimize(aMinimize) - , mChildrenPending() - , mNumProcessesRunning(1) // reporting starts with the parent - , mNumProcessesCompleted(0) - , mConcurrencyLimit(aConcurrencyLimit) - , mHandleReport(aHandleReport) - , mHandleReportData(aHandleReportData) - , mFinishReporting(aFinishReporting) - , mFinishReportingData(aFinishReportingData) - , mDMDDumpIdent(aDMDDumpIdent) +nsMemoryReporterManager::GetReportsState::~GetReportsState() { + delete mChildrenPending; } static void @@ -1831,7 +1767,7 @@ CrashIfRefcountIsZero(nsISupports* aObj) nsresult nsMemoryReporterManager::RegisterReporterHelper( - nsIMemoryReporter* aReporter, bool aForce, bool aStrong, bool aIsAsync) + nsIMemoryReporter* aReporter, bool aForce, bool aStrong) { // This method is thread-safe. mozilla::MutexAutoLock autoLock(mMutex); @@ -1858,7 +1794,7 @@ nsMemoryReporterManager::RegisterReporterHelper( // if (aStrong) { nsCOMPtr kungFuDeathGrip = aReporter; - mStrongReporters->Put(aReporter, aIsAsync); + mStrongReporters->PutEntry(aReporter); CrashIfRefcountIsZero(aReporter); } else { CrashIfRefcountIsZero(aReporter); @@ -1871,7 +1807,7 @@ nsMemoryReporterManager::RegisterReporterHelper( // CollectReports(). return NS_ERROR_XPC_BAD_CONVERT_JS; } - mWeakReporters->Put(aReporter, aIsAsync); + mWeakReporters->PutEntry(aReporter); } return NS_OK; @@ -1881,32 +1817,14 @@ NS_IMETHODIMP nsMemoryReporterManager::RegisterStrongReporter(nsIMemoryReporter* aReporter) { return RegisterReporterHelper(aReporter, /* force = */ false, - /* strong = */ true, - /* async = */ false); -} - -NS_IMETHODIMP -nsMemoryReporterManager::RegisterStrongAsyncReporter(nsIMemoryReporter* aReporter) -{ - return RegisterReporterHelper(aReporter, /* force = */ false, - /* strong = */ true, - /* async = */ true); + /* strong = */ true); } NS_IMETHODIMP nsMemoryReporterManager::RegisterWeakReporter(nsIMemoryReporter* aReporter) { return RegisterReporterHelper(aReporter, /* force = */ false, - /* strong = */ false, - /* async = */ false); -} - -NS_IMETHODIMP -nsMemoryReporterManager::RegisterWeakAsyncReporter(nsIMemoryReporter* aReporter) -{ - return RegisterReporterHelper(aReporter, /* force = */ false, - /* strong = */ false, - /* async = */ true); + /* strong = */ false); } NS_IMETHODIMP @@ -1914,8 +1832,7 @@ nsMemoryReporterManager::RegisterStrongReporterEvenIfBlocked( nsIMemoryReporter* aReporter) { return RegisterReporterHelper(aReporter, /* force = */ true, - /* strong = */ true, - /* async = */ false); + /* strong = */ true); } NS_IMETHODIMP @@ -1927,7 +1844,7 @@ nsMemoryReporterManager::UnregisterStrongReporter(nsIMemoryReporter* aReporter) MOZ_ASSERT(!mWeakReporters->Contains(aReporter)); if (mStrongReporters->Contains(aReporter)) { - mStrongReporters->Remove(aReporter); + mStrongReporters->RemoveEntry(aReporter); return NS_OK; } @@ -1936,7 +1853,7 @@ nsMemoryReporterManager::UnregisterStrongReporter(nsIMemoryReporter* aReporter) // references that these reporters aren't expecting (which can keep them // alive longer than intended). if (mSavedStrongReporters && mSavedStrongReporters->Contains(aReporter)) { - mSavedStrongReporters->Remove(aReporter); + mSavedStrongReporters->RemoveEntry(aReporter); return NS_OK; } @@ -1952,7 +1869,7 @@ nsMemoryReporterManager::UnregisterWeakReporter(nsIMemoryReporter* aReporter) MOZ_ASSERT(!mStrongReporters->Contains(aReporter)); if (mWeakReporters->Contains(aReporter)) { - mWeakReporters->Remove(aReporter); + mWeakReporters->RemoveEntry(aReporter); return NS_OK; } @@ -1961,7 +1878,7 @@ nsMemoryReporterManager::UnregisterWeakReporter(nsIMemoryReporter* aReporter) // references that the old reporters aren't expecting (which can end up as // dangling pointers that lead to use-after-frees). if (mSavedWeakReporters && mSavedWeakReporters->Contains(aReporter)) { - mSavedWeakReporters->Remove(aReporter); + mSavedWeakReporters->RemoveEntry(aReporter); return NS_OK; } @@ -2010,6 +1927,84 @@ nsMemoryReporterManager::UnblockRegistrationAndRestoreOriginalReporters() return NS_OK; } +// This is just a wrapper for int64_t that implements nsISupports, so it can be +// passed to nsIMemoryReporter::CollectReports. +class Int64Wrapper final : public nsISupports +{ + ~Int64Wrapper() {} + +public: + NS_DECL_ISUPPORTS + Int64Wrapper() : mValue(0) + { + } + int64_t mValue; +}; + +NS_IMPL_ISUPPORTS0(Int64Wrapper) + +class ExplicitCallback final : public nsIHandleReportCallback +{ + ~ExplicitCallback() {} + +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD Callback(const nsACString& aProcess, const nsACString& aPath, + int32_t aKind, int32_t aUnits, int64_t aAmount, + const nsACString& aDescription, + nsISupports* aWrappedExplicit) override + { + // Using the "heap-allocated" reporter here instead of + // nsMemoryReporterManager.heapAllocated goes against the usual + // pattern. But it's for a good reason: in tests, we can easily + // create artificial (i.e. deterministic) reporters -- which allows us + // to precisely test nsMemoryReporterManager.explicit -- but we can't + // do that for distinguished amounts. + if (aPath.EqualsLiteral("heap-allocated") || + (aKind == nsIMemoryReporter::KIND_NONHEAP && + PromiseFlatCString(aPath).Find("explicit") == 0)) { + Int64Wrapper* wrappedInt64 = static_cast(aWrappedExplicit); + wrappedInt64->mValue += aAmount; + } + return NS_OK; + } +}; + +NS_IMPL_ISUPPORTS(ExplicitCallback, nsIHandleReportCallback) + +NS_IMETHODIMP +nsMemoryReporterManager::GetExplicit(int64_t* aAmount) +{ + if (NS_WARN_IF(!aAmount)) { + return NS_ERROR_INVALID_ARG; + } + *aAmount = 0; +#ifndef HAVE_JEMALLOC_STATS + return NS_ERROR_NOT_AVAILABLE; +#else + + // For each reporter we call CollectReports and filter out the + // non-explicit, non-NONHEAP measurements (except for "heap-allocated"). + // That's lots of wasted work, and we used to have a GetExplicitNonHeap() + // method which did this more efficiently, but it ended up being more + // trouble than it was worth. + + nsRefPtr handleReport = new ExplicitCallback(); + nsRefPtr wrappedExplicitSize = new Int64Wrapper(); + + // Anonymization doesn't matter here, because we're only summing all the + // reported values. Enable it anyway because it's slightly faster, since it + // doesn't have to get URLs, find notable strings, etc. + GetReportsForThisProcess(handleReport, wrappedExplicitSize, + /* anonymize = */ true); + + *aAmount = wrappedExplicitSize->mValue; + + return NS_OK; +#endif // HAVE_JEMALLOC_STATS +} + NS_IMETHODIMP nsMemoryReporterManager::GetVsize(int64_t* aVsize) { @@ -2378,61 +2373,61 @@ nsMemoryReporterManager::SizeOfTab(nsIDOMWindow* aTopWindow, namespace mozilla { -#define GET_MEMORY_REPORTER_MANAGER(mgr) \ - nsRefPtr mgr = \ - nsMemoryReporterManager::GetOrCreate(); \ - if (!mgr) { \ - return NS_ERROR_FAILURE; \ - } - nsresult RegisterStrongMemoryReporter(nsIMemoryReporter* aReporter) { // Hold a strong reference to the argument to make sure it gets released if // we return early below. nsCOMPtr reporter = aReporter; - GET_MEMORY_REPORTER_MANAGER(mgr) - return mgr->RegisterStrongReporter(reporter); -} -nsresult -RegisterStrongAsyncMemoryReporter(nsIMemoryReporter* aReporter) -{ - // Hold a strong reference to the argument to make sure it gets released if - // we return early below. - nsCOMPtr reporter = aReporter; - GET_MEMORY_REPORTER_MANAGER(mgr) - return mgr->RegisterStrongAsyncReporter(reporter); + nsCOMPtr mgr = + do_GetService("@mozilla.org/memory-reporter-manager;1"); + if (!mgr) { + return NS_ERROR_FAILURE; + } + return mgr->RegisterStrongReporter(reporter); } nsresult RegisterWeakMemoryReporter(nsIMemoryReporter* aReporter) { - GET_MEMORY_REPORTER_MANAGER(mgr) + nsCOMPtr mgr = + do_GetService("@mozilla.org/memory-reporter-manager;1"); + if (!mgr) { + return NS_ERROR_FAILURE; + } return mgr->RegisterWeakReporter(aReporter); } -nsresult -RegisterWeakAsyncMemoryReporter(nsIMemoryReporter* aReporter) -{ - GET_MEMORY_REPORTER_MANAGER(mgr) - return mgr->RegisterWeakAsyncReporter(aReporter); -} - nsresult UnregisterStrongMemoryReporter(nsIMemoryReporter* aReporter) { - GET_MEMORY_REPORTER_MANAGER(mgr) + nsCOMPtr mgr = + do_GetService("@mozilla.org/memory-reporter-manager;1"); + if (!mgr) { + return NS_ERROR_FAILURE; + } return mgr->UnregisterStrongReporter(aReporter); } nsresult UnregisterWeakMemoryReporter(nsIMemoryReporter* aReporter) { - GET_MEMORY_REPORTER_MANAGER(mgr) + nsCOMPtr mgr = + do_GetService("@mozilla.org/memory-reporter-manager;1"); + if (!mgr) { + return NS_ERROR_FAILURE; + } return mgr->UnregisterWeakReporter(aReporter); } +#define GET_MEMORY_REPORTER_MANAGER(mgr) \ + nsRefPtr mgr = \ + nsMemoryReporterManager::GetOrCreate(); \ + if (!mgr) { \ + return NS_ERROR_FAILURE; \ + } + // Macro for generating functions that register distinguished amount functions // with the memory reporter manager. #define DEFINE_REGISTER_DISTINGUISHED_AMOUNT(kind, name) \ @@ -2488,3 +2483,45 @@ DEFINE_REGISTER_SIZE_OF_TAB(NonJS); #undef GET_MEMORY_REPORTER_MANAGER } // namespace mozilla + +#if defined(MOZ_DMD) + +namespace mozilla { +namespace dmd { + +class DoNothingCallback final : public nsIHandleReportCallback +{ +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD Callback(const nsACString& aProcess, const nsACString& aPath, + int32_t aKind, int32_t aUnits, int64_t aAmount, + const nsACString& aDescription, + nsISupports* aData) override + { + // Do nothing; the reporter has already reported to DMD. + return NS_OK; + } + +private: + ~DoNothingCallback() {} +}; + +NS_IMPL_ISUPPORTS(DoNothingCallback, nsIHandleReportCallback) + +void +RunReportersForThisProcess() +{ + nsCOMPtr mgr = + do_GetService("@mozilla.org/memory-reporter-manager;1"); + + nsRefPtr doNothing = new DoNothingCallback(); + + mgr->GetReportsForThisProcess(doNothing, nullptr, /* anonymize = */ false); +} + +} // namespace dmd +} // namespace mozilla + +#endif // defined(MOZ_DMD) + diff --git a/xpcom/base/nsMemoryReporterManager.h b/xpcom/base/nsMemoryReporterManager.h index 16af7b53f240..152e83a69b13 100644 --- a/xpcom/base/nsMemoryReporterManager.h +++ b/xpcom/base/nsMemoryReporterManager.h @@ -41,14 +41,14 @@ public: return static_cast(imgr.get()); } - typedef nsDataHashtable, bool> StrongReportersTable; - typedef nsDataHashtable, bool> WeakReportersTable; + typedef nsTHashtable> StrongReportersTable; + typedef nsTHashtable> WeakReportersTable; // Inter-process memory reporting proceeds as follows. // // - GetReports() (declared within NS_DECL_NSIMEMORYREPORTERMANAGER) // synchronously gets memory reports for the current process, sets up some - // state (mPendingProcessesState) for when child processes report back -- + // state (mGetReportsState) for when child processes report back -- // including a timer -- and starts telling child processes to get memory // reports. Control then returns to the main event loop. // @@ -108,7 +108,7 @@ public: // is incomplete. // // Now, what what happens if a child process is created/destroyed in the - // middle of a request? Well, PendingProcessesState is initialized with an array + // middle of a request? Well, GetReportsState is initialized with an array // of child process actors as of when the report started. So... // // - If a process is created after reporting starts, it won't be sent a @@ -184,15 +184,10 @@ public: private: nsresult RegisterReporterHelper(nsIMemoryReporter* aReporter, - bool aForce, bool aStrongRef, bool aIsAsync); + bool aForce, bool aStrongRef); nsresult StartGettingReports(); nsresult FinishReporting(); - void DispatchReporter(nsIMemoryReporter* aReporter, bool aIsAsync, - nsIHandleReportCallback* aHandleReport, - nsISupports* aHandleReportData, - bool aAnonymize); - static void TimeoutCallback(nsITimer* aTimer, void* aData); // Note: this timeout needs to be long enough to allow for the // possibility of DMD reports and/or running on a low-end phone. @@ -210,16 +205,16 @@ private: uint32_t mNextGeneration; - // Used to keep track of state of which processes are currently running and - // waiting to run memory reports. Holds references to parameters needed when - // requesting a memory report and finishing reporting. - struct PendingProcessesState + struct GetReportsState { uint32_t mGeneration; bool mAnonymize; bool mMinimize; nsCOMPtr mTimer; - nsTArray> mChildrenPending; + // This is a pointer to an nsTArray because otherwise C++ is + // unhappy unless this header includes ContentParent.h, which not + // everything that includes this header knows how to find. + nsTArray>* mChildrenPending; uint32_t mNumProcessesRunning; uint32_t mNumProcessesCompleted; uint32_t mConcurrencyLimit; @@ -229,52 +224,39 @@ private: nsCOMPtr mFinishReportingData; nsString mDMDDumpIdent; - PendingProcessesState(uint32_t aGeneration, bool aAnonymize, bool aMinimize, - uint32_t aConcurrencyLimit, - nsIHandleReportCallback* aHandleReport, - nsISupports* aHandleReportData, - nsIFinishReportingCallback* aFinishReporting, - nsISupports* aFinishReportingData, - const nsAString& aDMDDumpIdent); - }; - - // Used to keep track of the state of the asynchronously run memory - // reporters. The callback and file handle used when all memory reporters - // have finished are also stored here. - struct PendingReportersState - { - // Number of memory reporters currently running. - uint32_t mReportsPending; - - // Callback for when all memory reporters have completed. - nsCOMPtr mFinishReporting; - nsCOMPtr mFinishReportingData; - - // File handle to write a DMD report to if requested. - FILE* mDMDFile; - - PendingReportersState(nsIFinishReportingCallback* aFinishReporting, - nsISupports* aFinishReportingData, - FILE* aDMDFile) - : mReportsPending(0) + GetReportsState(uint32_t aGeneration, bool aAnonymize, bool aMinimize, + uint32_t aConcurrencyLimit, + nsIHandleReportCallback* aHandleReport, + nsISupports* aHandleReportData, + nsIFinishReportingCallback* aFinishReporting, + nsISupports* aFinishReportingData, + const nsAString& aDMDDumpIdent) + : mGeneration(aGeneration) + , mAnonymize(aAnonymize) + , mMinimize(aMinimize) + , mChildrenPending(nullptr) + , mNumProcessesRunning(1) // reporting starts with the parent + , mNumProcessesCompleted(0) + , mConcurrencyLimit(aConcurrencyLimit) + , mHandleReport(aHandleReport) + , mHandleReportData(aHandleReportData) , mFinishReporting(aFinishReporting) , mFinishReportingData(aFinishReportingData) - , mDMDFile(aDMDFile) + , mDMDDumpIdent(aDMDDumpIdent) { } + + ~GetReportsState(); }; // When this is non-null, a request is in flight. Note: We use manual // new/delete for this because its lifetime doesn't match block scope or // anything like that. - PendingProcessesState* mPendingProcessesState; + GetReportsState* mGetReportsState; - // This is reinitialized each time a call to GetReports is initiated. - PendingReportersState* mPendingReportersState; - - PendingProcessesState* GetStateForGeneration(uint32_t aGeneration); + GetReportsState* GetStateForGeneration(uint32_t aGeneration); static bool StartChildReport(mozilla::dom::ContentParent* aChild, - const PendingProcessesState* aState); + const GetReportsState* aState); }; #define NS_MEMORY_REPORTER_MANAGER_CID \ From 69fba7ebc6dd895d7a7fc03c71e6e41304d9a7e2 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Thu, 3 Sep 2015 15:55:46 +0100 Subject: [PATCH 098/228] Bug 1209975 - Stop using dom::Promise::MaybeRejectBrokenly() in GetDirectoryListingTask. r=baku --- dom/filesystem/GetDirectoryListingTask.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/dom/filesystem/GetDirectoryListingTask.cpp b/dom/filesystem/GetDirectoryListingTask.cpp index 9fdb120ab979..f0b8bbbaa5d8 100644 --- a/dom/filesystem/GetDirectoryListingTask.cpp +++ b/dom/filesystem/GetDirectoryListingTask.cpp @@ -8,7 +8,6 @@ #include "js/Value.h" #include "mozilla/dom/Directory.h" -#include "mozilla/dom/DOMError.h" #include "mozilla/dom/File.h" #include "mozilla/dom/FileSystemBase.h" #include "mozilla/dom/FileSystemUtils.h" @@ -197,9 +196,7 @@ GetDirectoryListingTask::HandlerCallback() } if (HasError()) { - nsRefPtr domError = new DOMError(mFileSystem->GetWindow(), - mErrorValue); - mPromise->MaybeRejectBrokenly(domError); + mPromise->MaybeReject(mErrorValue); mPromise = nullptr; return; } From 3898c2479786681a4b03adfd5d8298c944975bb3 Mon Sep 17 00:00:00 2001 From: Kit Cambridge Date: Tue, 6 Oct 2015 08:14:25 -0700 Subject: [PATCH 099/228] Bug 1191453 - Drop subscriptions for a site when the user revokes push permissions. r=mt,MattN --HG-- extra : commitid : JlZvX8xAxRf extra : rebase_source : 14372dacf2d519784890550a0e77d4c05e4f2c1a --- dom/push/PushDB.jsm | 29 ++ dom/push/PushRecord.jsm | 16 +- dom/push/PushService.jsm | 220 ++++++++++---- dom/push/PushServiceHttp2.jsm | 4 + dom/push/PushServiceWebSocket.jsm | 4 + dom/push/test/xpcshell/test_permissions.js | 268 ++++++++++++++++++ dom/push/test/xpcshell/test_quota_observer.js | 26 +- .../test/xpcshell/test_webapps_cleardata.js | 11 +- dom/push/test/xpcshell/xpcshell.ini | 6 +- 9 files changed, 521 insertions(+), 63 deletions(-) create mode 100644 dom/push/test/xpcshell/test_permissions.js diff --git a/dom/push/PushDB.jsm b/dom/push/PushDB.jsm index baf925c33402..659741197dbf 100644 --- a/dom/push/PushDB.jsm +++ b/dom/push/PushDB.jsm @@ -227,6 +227,35 @@ this.PushDB.prototype = { ); }, + getAllByOrigin: function(origin, originAttributes) { + debug("getAllByOrigin()"); + + return new Promise((resolve, reject) => + this.newTxn( + "readonly", + this._dbStoreName, + (aTxn, aStore) => { + aTxn.result = []; + + let index = aStore.index("identifiers"); + let range = IDBKeyRange.bound( + [origin, originAttributes], + [origin + "\x7f", originAttributes] + ); + index.openCursor(range).onsuccess = event => { + let cursor = event.target.result; + if (cursor) { + aTxn.result.push(this.toPushRecord(cursor.value)); + cursor.continue(); + } + }; + }, + resolve, + reject + ) + ); + }, + // Perform a unique match against { scope, originAttributes } getByIdentifiers: function(aPageRecord) { debug("getByIdentifiers() { " + aPageRecord.scope + ", " + diff --git a/dom/push/PushRecord.jsm b/dom/push/PushRecord.jsm index 4c002b122841..2f05a9bd718a 100644 --- a/dom/push/PushRecord.jsm +++ b/dom/push/PushRecord.jsm @@ -50,8 +50,15 @@ function PushRecord(props) { PushRecord.prototype = { setQuota(suggestedQuota) { - this.quota = (!isNaN(suggestedQuota) && suggestedQuota >= 0) ? - suggestedQuota : prefs.get("maxQuotaPerSubscription"); + if (!isNaN(suggestedQuota) && suggestedQuota >= 0) { + this.quota = suggestedQuota; + } else { + this.resetQuota(); + } + }, + + resetQuota() { + this.quota = prefs.get("maxQuotaPerSubscription"); }, updateQuota(lastVisit) { @@ -170,6 +177,11 @@ PushRecord.prototype = { return permission == Ci.nsIPermissionManager.ALLOW_ACTION; }, + quotaChanged() { + return this.getLastVisit() + .then(lastVisit => lastVisit > this.lastPush); + }, + quotaApplies() { return Number.isFinite(this.quota); }, diff --git a/dom/push/PushService.jsm b/dom/push/PushService.jsm index 186db4fffc17..dad7e7289827 100644 --- a/dom/push/PushService.jsm +++ b/dom/push/PushService.jsm @@ -261,6 +261,13 @@ this.PushService = { this._dropExpiredRegistrations(); break; + case "perm-changed": + this._onPermissionChange(aSubject, aData).catch(error => { + debug("onPermissionChange: Error updating registrations: " + + error); + }) + break; + case "webapps-clear-data": debug("webapps-clear-data"); @@ -276,43 +283,34 @@ this.PushService = { ChromeUtils.originAttributesToSuffix({ appId: data.appId, inBrowser: data.browserOnly }); this._db.getAllByOriginAttributes(originAttributes) - .then(records => { - records.forEach(record => { - this._db.delete(record.keyID) - .then(_ => { - // courtesy, but don't establish a connection - // just for it - if (this._ws) { - debug("Had a connection, so telling the server"); - this._sendUnregister({channelID: record.channelID}) - .catch(function(e) { - debug("Unregister errored " + e); - }); - } - }, err => { - debug("webapps-clear-data: " + record.scope + - " Could not delete entry " + record.channelID); + .then(records => Promise.all(records.map(record => + this._db.delete(record.keyID).then( + _ => this._unregisterIfConnected(record), + err => { + debug("webapps-clear-data: " + record.scope + + " Could not delete entry " + record.channelID); - // courtesy, but don't establish a connection - // just for it - if (this._ws) { - debug("Had a connection, so telling the server"); - this._sendUnregister({channelID: record.channelID}) - .catch(function(e) { - debug("Unregister errored " + e); - }); - } - throw "Database error"; - }); - }); - }, _ => { - debug("webapps-clear-data: Error in getAllByOriginAttributes(" + originAttributes + ")"); - }); + return this._unregisterIfConnected(record); + }) + ) + )); break; } }, + _unregisterIfConnected: function(record) { + if (this._service.isConnected()) { + // courtesy, but don't establish a connection + // just for it + debug("Had a connection, so telling the server"); + return this._sendUnregister({channelID: record.channelID}) + .catch(function(e) { + debug("Unregister errored " + e); + }); + } + }, + // utility function used to add/remove observers in startObservers() and // stopObservers() getNetworkStateChangeEventName: function() { @@ -499,8 +497,12 @@ this.PushService = { // Used to monitor if the user wishes to disable Push. prefs.observe("connection.enabled", this); - // Used to prune expired registrations and notify dormant service workers. + // Prunes expired registrations and notifies dormant service workers. Services.obs.addObserver(this, "idle-daily", false); + + // Prunes registrations for sites for which the user revokes push + // permissions. + Services.obs.addObserver(this, "perm-changed", false); }, _startService: function(service, serverURI, event, options = {}) { @@ -530,7 +532,7 @@ this.PushService = { this._service.init(options, this, serverURI); this._startObservers(); - return Promise.resolve(); + return this._dropExpiredRegistrations(); }, /** @@ -599,6 +601,7 @@ this.PushService = { Services.obs.removeObserver(this, this._networkStateChangeEventName); Services.obs.removeObserver(this, "webapps-clear-data"); Services.obs.removeObserver(this, "idle-daily"); + Services.obs.removeObserver(this, "perm-changed"); }, uninit: function() { @@ -758,6 +761,11 @@ this.PushService = { }); }, + dropRecordAndNotifyApp: function(aRecord) { + return this._db.delete(aRecord.keyID) + .then(_ => this._notifySubscriptionChangeObservers(aRecord)); + }, + _recordDidNotNotify: function(reason) { Services.telemetry. getHistogramById("PUSH_API_NOTIFICATION_RECEIVED_BUT_DID_NOT_NOTIFY"). @@ -951,16 +959,14 @@ this.PushService = { return this._lookupOrPutPendingRequest(aPageRecord); } if (record.isExpired()) { - return record.getLastVisit().then(lastVisit => { - if (lastVisit > record.lastPush) { + return record.quotaChanged().then(isChanged => { + if (isChanged) { // If the user revisited the site, drop the expired push // registration and re-register. - return this._db.delete(record.keyID).then(_ => { - return this._lookupOrPutPendingRequest(aPageRecord); - }); + return this._db.delete(record.keyID); } throw {state: 0, error: "NotFoundError"}; - }); + }).then(_ => this._lookupOrPutPendingRequest(aPageRecord)); } return record; }, error => { @@ -1221,12 +1227,12 @@ this.PushService = { return null; } if (record.isExpired()) { - return record.getLastVisit().then(lastVisit => { - if (lastVisit > record.lastPush) { - return this._db.delete(record.keyID).then(_ => null); + return record.quotaChanged().then(isChanged => { + if (isChanged) { + return this._db.delete(record.keyID); } throw {state: 0, error: "NotFoundError"}; - }); + }).then(_ => null); } return record.toRegistration(); }); @@ -1251,24 +1257,130 @@ this.PushService = { _dropExpiredRegistrations: function() { debug("dropExpiredRegistrations()"); - this._db.getAllExpired().then(records => { - return Promise.all(records.map(record => { - return record.getLastVisit().then(lastVisit => { - if (lastVisit > record.lastPush) { + return this._db.getAllExpired().then(records => { + return Promise.all(records.map(record => + record.quotaChanged().then(isChanged => { + if (isChanged) { // If the user revisited the site, drop the expired push // registration and notify the associated service worker. - return this._db.delete(record.keyID).then(() => { - this._notifySubscriptionChangeObservers(record); - }); + return this.dropRecordAndNotifyApp(record); } }).catch(error => { debug("dropExpiredRegistrations: Error dropping registration " + record.keyID + ": " + error); - }); - })); + }) + )); + }); + }, + + _onPermissionChange: function(subject, data) { + debug("onPermissionChange()"); + + if (data == "cleared") { + // If the permission list was cleared, drop all registrations + // that are subject to quota. + return this._db.clearIf(record => { + if (record.quotaApplies()) { + if (!record.isExpired()) { + // Drop the registration in the background. + this._unregisterIfConnected(record); + } + return true; + } + return false; + }); + } + + let permission = subject.QueryInterface(Ci.nsIPermission); + if (permission.type != "push") { + return Promise.resolve(); + } + + return this._updatePermission(permission, data); + }, + + _updatePermission: function(permission, type) { + debug("updatePermission()"); + + let isAllow = permission.capability == + Ci.nsIPermissionManager.ALLOW_ACTION; + let isChange = type == "added" || type == "changed"; + + if (isAllow && isChange) { + // Permission set to "allow". Drop all expired registrations for this + // site, notify the associated service workers, and reset the quota + // for active registrations. + return this._getByPrincipal(permission.principal) + .then(records => this._permissionAllowed(records)); + } else if (isChange || (isAllow && type == "deleted")) { + // Permission set to "block" or "always ask," or "allow" permission + // removed. Expire all registrations for this site. + return this._getByPrincipal(permission.principal) + .then(records => this._permissionDenied(records)); + } + + return Promise.resolve(); + }, + + _getByPrincipal: function(principal) { + return this._db.getAllByOrigin( + principal.URI.prePath, + ChromeUtils.originAttributesToSuffix(principal.originAttributes) + ); + }, + + /** + * Expires all registrations if the push permission is revoked. We only + * expire the registration so we can notify the service worker as soon as + * the permission is reinstated. If we just deleted the registration, the + * worker wouldn't be notified until the next visit to the site. + * + * @param {Array} A list of records to expire. + * @returns {Promise} A promise resolved with the expired records. + */ + _permissionDenied: function(records) { + return Promise.all(records.filter(record => + // Ignore already-expired records. + record.quotaApplies() && !record.isExpired() + ).map(record => + this._expireRegistration(record) + )); + }, + + /** + * Drops all expired registrations, notifies the associated service + * workers, and resets the quota for active registrations if the push + * permission is granted. + * + * @param {Array} A list of records to refresh. + * @returns {Promise} A promise resolved with the refreshed records. + */ + _permissionAllowed: function(records) { + return Promise.all(records.map(record => { + if (!record.quotaApplies()) { + return record; + } + if (record.isExpired()) { + // If the registration has expired, drop and notify the worker + // unconditionally. + return this.dropRecordAndNotifyApp(record); + } + return this._db.update(record.keyID, record => { + record.resetQuota(); + return record; + }); + })); + }, + + _expireRegistration: function(record) { + // Drop the registration in the background. + this._unregisterIfConnected(record); + return this._db.update(record.keyID, record => { + record.setQuota(0); + return record; }).catch(error => { - debug("dropExpiredRegistrations: Error dropping registrations: " + - error); + debug("expireRegistration: Error dropping expired registration " + + record.keyID + ": " + error); }); }, }; diff --git a/dom/push/PushServiceHttp2.jsm b/dom/push/PushServiceHttp2.jsm index 1f6719798904..5d4fea9a0d8b 100644 --- a/dom/push/PushServiceHttp2.jsm +++ b/dom/push/PushServiceHttp2.jsm @@ -479,6 +479,10 @@ this.PushServiceHttp2 = { this.startConnections(subscriptions); }, + isConnected: function() { + return this._mainPushService != null; + }, + disconnect: function() { this._shutdownConnections(false); }, diff --git a/dom/push/PushServiceWebSocket.jsm b/dom/push/PushServiceWebSocket.jsm index dc022ed4073d..30db1e910bcc 100644 --- a/dom/push/PushServiceWebSocket.jsm +++ b/dom/push/PushServiceWebSocket.jsm @@ -649,6 +649,10 @@ this.PushServiceWebSocket = { } }, + isConnected: function() { + return !!this._ws; + }, + /** * There is only one alarm active at any time. This alarm has 3 intervals * corresponding to 3 tasks. diff --git a/dom/push/test/xpcshell/test_permissions.js b/dom/push/test/xpcshell/test_permissions.js new file mode 100644 index 000000000000..21abbe3b813f --- /dev/null +++ b/dom/push/test/xpcshell/test_permissions.js @@ -0,0 +1,268 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +'use strict'; + +const {PushDB, PushService, PushServiceWebSocket} = serviceExports; + +const userAgentID = '2c43af06-ab6e-476a-adc4-16cbda54fb89'; + +let db; + +function run_test() { + do_get_profile(); + setPrefs({ + userAgentID, + }); + + db = PushServiceWebSocket.newPushDB(); + do_register_cleanup(() => {return db.drop().then(_ => db.close());}); + + run_next_test(); +} + +let unregisterDefers = {}; + +function putRecord(channelID, scope, quota) { + return db.put({ + channelID: channelID, + pushEndpoint: 'https://example.org/push/' + channelID, + scope: scope, + pushCount: 0, + lastPush: 0, + version: null, + originAttributes: '', + quota: quota, + }); +} + +function makePushPermission(url, capability) { + return { + QueryInterface: XPCOMUtils.generateQI([Ci.nsIPermission]), + capability: Ci.nsIPermissionManager[capability], + expireTime: 0, + expireType: Ci.nsIPermissionManager.EXPIRE_NEVER, + principal: Services.scriptSecurityManager.getCodebasePrincipal( + Services.io.newURI(url, null, null) + ), + type: 'push', + }; +} + +function promiseSubscriptionChanges(count) { + let notifiedScopes = []; + let subChangePromise = promiseObserverNotification('push-subscription-change', (subject, data) => { + notifiedScopes.push(data); + return notifiedScopes.length == count; + }); + return subChangePromise.then(_ => notifiedScopes.sort()); +} + +function allExpired(...keyIDs) { + return Promise.all(keyIDs.map( + keyID => db.getByKeyID(keyID) + )).then(records => + records.every(record => record.isExpired()) + ); +} + +add_task(function* setUp() { + // Active registration; quota should be reset to 16. Since the quota isn't + // exposed to content, we shouldn't receive a subscription change event. + yield putRecord('active-allow', 'https://example.info/page/1', 8); + + // Expired registration; should be dropped. + yield putRecord('expired-allow', 'https://example.info/page/2', 0); + + // Active registration; should be expired when we change the permission + // to "deny". + yield putRecord('active-deny-changed', 'https://example.xyz/page/1', 16); + + // Two active registrations for a visited site. These will expire when we + // add a "deny" permission. + yield putRecord('active-deny-added-1', 'https://example.net/ham', 16); + yield putRecord('active-deny-added-2', 'https://example.net/green', 8); + + // An already-expired registration for a visited site. We shouldn't send an + // `unregister` request for this one, but still receive an observer + // notification when we restore permissions. + yield putRecord('expired-deny-added', 'https://example.net/eggs', 0); + + // A registration that should not be affected by permission list changes + // because its quota is set to `Infinity`. + yield putRecord('never-expires', 'app://chrome/only', Infinity); + + // A registration that should be dropped when we clear the permission + // list. + yield putRecord('drop-on-clear', 'https://example.edu/lonely', 16); + + let handshakeDone; + let handshakePromise = new Promise(resolve => handshakeDone = resolve); + PushService.init({ + serverURI: 'wss://push.example.org/', + networkInfo: new MockDesktopNetworkInfo(), + db, + makeWebSocket(uri) { + return new MockWebSocket(uri, { + onHello(request) { + this.serverSendMsg(JSON.stringify({ + messageType: 'hello', + status: 200, + uaid: userAgentID, + })); + handshakeDone(); + }, + onUnregister(request) { + let resolve = unregisterDefers[request.channelID]; + equal(typeof resolve, 'function', + 'Dropped unexpected channel ID ' + request.channelID); + delete unregisterDefers[request.channelID]; + resolve(); + }, + onACK(request) {}, + }); + } + }); + yield waitForPromise(handshakePromise, DEFAULT_TIMEOUT, + 'Timed out waiting for handshake'); +}); + +add_task(function* test_permissions_allow_added() { + let subChangePromise = promiseSubscriptionChanges(1); + + yield PushService._onPermissionChange( + makePushPermission('https://example.info', 'ALLOW_ACTION'), + 'added' + ); + let notifiedScopes = yield waitForPromise(subChangePromise, DEFAULT_TIMEOUT, + 'Timed out waiting for notifications after adding allow'); + + deepEqual(notifiedScopes, [ + 'https://example.info/page/2', + ], 'Wrong scopes after adding allow'); + + let record = yield db.getByKeyID('active-allow'); + equal(record.quota, 16, + 'Should reset quota for active records after adding allow'); + + record = yield db.getByKeyID('expired-allow'); + ok(!record, 'Should drop expired records after adding allow'); +}); + +add_task(function* test_permissions_allow_deleted() { + let unregisterPromise = new Promise(resolve => unregisterDefers[ + 'active-allow'] = resolve); + + yield PushService._onPermissionChange( + makePushPermission('https://example.info', 'ALLOW_ACTION'), + 'deleted' + ); + + yield waitForPromise(unregisterPromise, DEFAULT_TIMEOUT, + 'Timed out waiting for unregister after deleting allow'); + + let record = yield db.getByKeyID('active-allow'); + ok(record.isExpired(), + 'Should expire active record after deleting allow'); +}); + +add_task(function* test_permissions_deny_added() { + let unregisterPromise = Promise.all([ + new Promise(resolve => unregisterDefers[ + 'active-deny-added-1'] = resolve), + new Promise(resolve => unregisterDefers[ + 'active-deny-added-2'] = resolve), + ]); + + yield PushService._onPermissionChange( + makePushPermission('https://example.net', 'DENY_ACTION'), + 'added' + ); + yield waitForPromise(unregisterPromise, DEFAULT_TIMEOUT, + 'Timed out waiting for notifications after adding deny'); + + let isExpired = yield allExpired( + 'active-deny-added-1', + 'expired-deny-added' + ); + ok(isExpired, 'Should expire all registrations after adding deny'); +}); + +add_task(function* test_permissions_deny_deleted() { + yield PushService._onPermissionChange( + makePushPermission('https://example.net', 'DENY_ACTION'), + 'deleted' + ); + + let isExpired = yield allExpired( + 'active-deny-added-1', + 'expired-deny-added' + ); + ok(isExpired, 'Should retain expired registrations after deleting deny'); +}); + +add_task(function* test_permissions_allow_changed() { + let subChangePromise = promiseSubscriptionChanges(3); + + yield PushService._onPermissionChange( + makePushPermission('https://example.net', 'ALLOW_ACTION'), + 'changed' + ); + + let notifiedScopes = yield waitForPromise(subChangePromise, DEFAULT_TIMEOUT, + 'Timed out waiting for notifications after changing to allow'); + + deepEqual(notifiedScopes, [ + 'https://example.net/eggs', + 'https://example.net/green', + 'https://example.net/ham' + ], 'Wrong scopes after changing to allow'); + + let droppedRecords = yield Promise.all([ + db.getByKeyID('active-deny-added-1'), + db.getByKeyID('active-deny-added-2'), + db.getByKeyID('expired-deny-added'), + ]); + ok(!droppedRecords.some(Boolean), + 'Should drop all expired registrations after changing to allow'); +}); + +add_task(function* test_permissions_deny_changed() { + let unregisterPromise = new Promise(resolve => unregisterDefers[ + 'active-deny-changed'] = resolve); + + yield PushService._onPermissionChange( + makePushPermission('https://example.xyz', 'DENY_ACTION'), + 'changed' + ); + + yield waitForPromise(unregisterPromise, DEFAULT_TIMEOUT, + 'Timed out waiting for unregister after changing to deny'); + + let record = yield db.getByKeyID('active-deny-changed'); + ok(record.isExpired(), + 'Should expire active record after changing to allow'); +}); + +add_task(function* test_permissions_clear() { + let records = yield db.getAllKeyIDs(); + deepEqual(records.map(record => record.keyID).sort(), [ + 'active-allow', + 'active-deny-changed', + 'drop-on-clear', + 'never-expires', + ], 'Wrong records in database before clearing'); + + let unregisterPromise = new Promise(resolve => unregisterDefers[ + 'drop-on-clear'] = resolve); + + yield PushService._onPermissionChange(null, 'cleared'); + + yield waitForPromise(unregisterPromise, DEFAULT_TIMEOUT, + 'Timed out waiting for unregister requests after clearing permissions'); + + records = yield db.getAllKeyIDs(); + deepEqual(records.map(record => record.keyID).sort(), [ + 'never-expires', + ], 'Unrestricted registrations should not be dropped'); +}); diff --git a/dom/push/test/xpcshell/test_quota_observer.js b/dom/push/test/xpcshell/test_quota_observer.js index 9adb6f1e8457..d0cf2563cde5 100644 --- a/dom/push/test/xpcshell/test_quota_observer.js +++ b/dom/push/test/xpcshell/test_quota_observer.js @@ -31,11 +31,11 @@ add_task(function* test_expiration_history_observer() { quota: 16, }); - // ...And an expired registration that we'll revive later. + // ...And a registration that we'll evict on startup. yield db.put({ - channelID: 'eb33fc90-c883-4267-b5cb-613969e8e349', - pushEndpoint: 'https://example.org/push/2', - scope: 'https://example.com/auctions', + channelID: '4cb6e454-37cf-41c4-a013-4e3a7fdd0bf1', + pushEndpoint: 'https://example.org/push/3', + scope: 'https://example.com/stuff', pushCount: 0, lastPush: 0, version: null, @@ -54,6 +54,8 @@ add_task(function* test_expiration_history_observer() { let unregisterDone; let unregisterPromise = new Promise(resolve => unregisterDone = resolve); + let subChangePromise = promiseObserverNotification('push-subscription-change', (subject, data) => + data == 'https://example.com/stuff'); PushService.init({ serverURI: 'wss://push.example.org/', @@ -87,6 +89,8 @@ add_task(function* test_expiration_history_observer() { } }); + yield waitForPromise(subChangePromise, DEFAULT_TIMEOUT, + 'Timed out waiting for subscription change event on startup'); yield waitForPromise(unregisterPromise, DEFAULT_TIMEOUT, 'Timed out waiting for unregister request'); @@ -94,11 +98,23 @@ add_task(function* test_expiration_history_observer() { strictEqual(expiredRecord.quota, 0, 'Expired record not updated'); let notifiedScopes = []; - let subChangePromise = promiseObserverNotification('push-subscription-change', (subject, data) => { + subChangePromise = promiseObserverNotification('push-subscription-change', (subject, data) => { notifiedScopes.push(data); return notifiedScopes.length == 2; }); + // Add an expired registration that we'll revive later. + yield db.put({ + channelID: 'eb33fc90-c883-4267-b5cb-613969e8e349', + pushEndpoint: 'https://example.org/push/2', + scope: 'https://example.com/auctions', + pushCount: 0, + lastPush: 0, + version: null, + originAttributes: '', + quota: 0, + }); + // Now visit the site... yield addVisit({ uri: 'https://example.com/another-page', diff --git a/dom/push/test/xpcshell/test_webapps_cleardata.js b/dom/push/test/xpcshell/test_webapps_cleardata.js index 4d23f1859525..9a6e6fb0a3c6 100644 --- a/dom/push/test/xpcshell/test_webapps_cleardata.js +++ b/dom/push/test/xpcshell/test_webapps_cleardata.js @@ -26,6 +26,9 @@ add_task(function* test_webapps_cleardata() { let db = PushServiceWebSocket.newPushDB(); do_register_cleanup(() => {return db.drop().then(_ => db.close());}); + let unregisterDone; + let unregisterPromise = new Promise(resolve => unregisterDone = resolve); + PushService.init({ serverURI: "wss://push.example.org", networkInfo: new MockDesktopNetworkInfo(), @@ -50,7 +53,10 @@ add_task(function* test_webapps_cleardata() { uaid: userAgentID, pushEndpoint: 'https://example.com/update/' + Math.random(), })); - } + }, + onUnregister(data) { + unregisterDone(); + }, }); } }); @@ -84,5 +90,8 @@ add_task(function* test_webapps_cleardata() { 'https://example.org/1', ChromeUtils.originAttributesToSuffix({ appId: 1, inBrowser: true })); ok(registration, 'Registration for { 1, true } should still exist.'); + + yield waitForPromise(unregisterPromise, DEFAULT_TIMEOUT, + 'Timed out waiting for unregister'); }); diff --git a/dom/push/test/xpcshell/xpcshell.ini b/dom/push/test/xpcshell/xpcshell.ini index ff3a5162aa7c..c73c13331854 100644 --- a/dom/push/test/xpcshell/xpcshell.ini +++ b/dom/push/test/xpcshell/xpcshell.ini @@ -9,6 +9,10 @@ skip-if = toolkit == 'android' [test_notification_error.js] [test_notification_incomplete.js] [test_notification_version_string.js] + +[test_permissions.js] +run-sequentially = This will delete all existing push subscriptions. + [test_quota_exceeded.js] [test_quota_observer.js] [test_register_case.js] @@ -60,4 +64,4 @@ skip-if = !hasNode run-sequentially = node server exceptions dont replay well [test_clearAll_successful.js] skip-if = !hasNode -run-sequentially = This will delete all existing push subscritions. +run-sequentially = This will delete all existing push subscriptions. From 0d21d8c3b8a63291fe4d0e2bfcecb57ffabe68bf Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Tue, 6 Oct 2015 15:40:46 -0700 Subject: [PATCH 100/228] Bug 1212128 - Annotate oomInGetJumpLabelForBranch with allow-oom. (rs=terrence) --- js/src/jit-test/tests/gc/oomInGetJumpLabelForBranch.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/jit-test/tests/gc/oomInGetJumpLabelForBranch.js b/js/src/jit-test/tests/gc/oomInGetJumpLabelForBranch.js index 3e535f31d57e..501b71755d6c 100644 --- a/js/src/jit-test/tests/gc/oomInGetJumpLabelForBranch.js +++ b/js/src/jit-test/tests/gc/oomInGetJumpLabelForBranch.js @@ -1,3 +1,3 @@ -// |jit-test| --no-threads +// |jit-test| allow-oom; allow-unhandlable-oom; --no-threads load(libdir + 'oomTest.js'); oomTest(() => getBacktrace({thisprops: gc() && delete addDebuggee.enabled})); From 98513a1124879b97ac0820c26c2bb185fd2e83c8 Mon Sep 17 00:00:00 2001 From: Kevin Wern Date: Mon, 5 Oct 2015 11:47:01 -0400 Subject: [PATCH 101/228] Bug 1202050 - Use UntransformTo in a few more places in APZ code. r=botond We previously believed these matrices could only be 2D, but it turns out they can potentially be 3D projective transforms, so we need to use UntransformTo() when applying them. The patch also removes the unused function APZCTreeManager::TransformCoordinateToGecko(). --HG-- extra : rebase_source : e73862963df275036f35272b688f65c271ca659a extra : source : b04cab83c7f061b9b934d30f7e5adb831206972e --- gfx/layers/apz/src/APZCTreeManager.cpp | 80 ++++++++++--------- gfx/layers/apz/src/APZCTreeManager.h | 9 --- gfx/layers/apz/src/AsyncPanZoomController.cpp | 8 +- 3 files changed, 49 insertions(+), 48 deletions(-) diff --git a/gfx/layers/apz/src/APZCTreeManager.cpp b/gfx/layers/apz/src/APZCTreeManager.cpp index 65f6e367b574..5615a8d3847a 100644 --- a/gfx/layers/apz/src/APZCTreeManager.cpp +++ b/gfx/layers/apz/src/APZCTreeManager.cpp @@ -680,10 +680,13 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent, // gecko space should only consist of overscroll-cancelling transforms. Matrix4x4 transformToGecko = GetScreenToApzcTransform(apzc) * GetApzcToGeckoTransform(apzc); - MOZ_ASSERT(transformToGecko.Is2D()); - ScreenPoint untransformedOrigin = TransformTo( + Maybe untransformedOrigin = UntransformTo( transformToGecko, wheelInput.mOrigin); + if (!untransformedOrigin) { + return result; + } + result = mInputQueue->ReceiveInputEvent( apzc, /* aTargetConfirmed = */ hitResult == HitLayer, @@ -691,7 +694,7 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent, // Update the out-parameters so they are what the caller expects. apzc->GetGuid(aOutTargetGuid); - wheelInput.mOrigin = untransformedOrigin; + wheelInput.mOrigin = *untransformedOrigin; } break; } case PANGESTURE_INPUT: { @@ -717,12 +720,15 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent, // gecko space should only consist of overscroll-cancelling transforms. Matrix4x4 transformToGecko = GetScreenToApzcTransform(apzc) * GetApzcToGeckoTransform(apzc); - MOZ_ASSERT(transformToGecko.Is2D()); - ScreenPoint untransformedStartPoint = TransformTo( + Maybe untransformedStartPoint = UntransformTo( transformToGecko, panInput.mPanStartPoint); - ScreenPoint untransformedDisplacement = TransformVector( + Maybe untransformedDisplacement = UntransformVector( transformToGecko, panInput.mPanDisplacement, panInput.mPanStartPoint); + if (!untransformedStartPoint || !untransformedDisplacement) { + return result; + } + result = mInputQueue->ReceiveInputEvent( apzc, /* aTargetConfirmed = */ hitResult == HitLayer, @@ -730,8 +736,8 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent, // Update the out-parameters so they are what the caller expects. apzc->GetGuid(aOutTargetGuid); - panInput.mPanStartPoint = untransformedStartPoint; - panInput.mPanDisplacement = untransformedDisplacement; + panInput.mPanStartPoint = *untransformedStartPoint; + panInput.mPanDisplacement = *untransformedDisplacement; } break; } case PINCHGESTURE_INPUT: { // note: no one currently sends these @@ -741,6 +747,15 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent, if (apzc) { MOZ_ASSERT(hitResult == HitLayer || hitResult == HitDispatchToContentRegion); + Matrix4x4 outTransform = GetScreenToApzcTransform(apzc) + * GetApzcToGeckoTransform(apzc); + Maybe untransformedFocusPoint = UntransformTo( + outTransform, pinchInput.mFocusPoint); + + if (!untransformedFocusPoint) { + return result; + } + result = mInputQueue->ReceiveInputEvent( apzc, /* aTargetConfirmed = */ hitResult == HitLayer, @@ -748,11 +763,7 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent, // Update the out-parameters so they are what the caller expects. apzc->GetGuid(aOutTargetGuid); - Matrix4x4 outTransform = GetScreenToApzcTransform(apzc) - * GetApzcToGeckoTransform(apzc); - MOZ_ASSERT(outTransform.Is2D()); - pinchInput.mFocusPoint = TransformTo( - outTransform, pinchInput.mFocusPoint); + pinchInput.mFocusPoint = *untransformedFocusPoint; } break; } case TAPGESTURE_INPUT: { // note: no one currently sends these @@ -762,6 +773,15 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent, if (apzc) { MOZ_ASSERT(hitResult == HitLayer || hitResult == HitDispatchToContentRegion); + Matrix4x4 outTransform = GetScreenToApzcTransform(apzc) + * GetApzcToGeckoTransform(apzc); + Maybe untransformedPoint = + UntransformTo(outTransform, tapInput.mPoint); + + if (!untransformedPoint) { + return result; + } + result = mInputQueue->ReceiveInputEvent( apzc, /* aTargetConfirmed = */ hitResult == HitLayer, @@ -769,10 +789,7 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent, // Update the out-parameters so they are what the caller expects. apzc->GetGuid(aOutTargetGuid); - Matrix4x4 outTransform = GetScreenToApzcTransform(apzc) - * GetApzcToGeckoTransform(apzc); - MOZ_ASSERT(outTransform.Is2D()); - tapInput.mPoint = TransformTo(outTransform, tapInput.mPoint); + tapInput.mPoint = *untransformedPoint; } break; } @@ -864,12 +881,15 @@ APZCTreeManager::ProcessTouchInput(MultiTouchInput& aInput, Matrix4x4 transformToApzc = GetScreenToApzcTransform(mApzcForInputBlock); Matrix4x4 transformToGecko = GetApzcToGeckoTransform(mApzcForInputBlock); Matrix4x4 outTransform = transformToApzc * transformToGecko; - MOZ_ASSERT(outTransform.Is2D()); for (size_t i = 0; i < aInput.mTouches.Length(); i++) { SingleTouchData& touchData = aInput.mTouches[i]; - touchData.mScreenPoint = TransformTo( + Maybe untransformedScreenPoint = UntransformTo( outTransform, touchData.mScreenPoint); + if (!untransformedScreenPoint) { + return nsEventStatus_eIgnore; + } + touchData.mScreenPoint = *untransformedScreenPoint; } } @@ -886,21 +906,6 @@ APZCTreeManager::ProcessTouchInput(MultiTouchInput& aInput, return result; } -void -APZCTreeManager::TransformCoordinateToGecko(const ScreenIntPoint& aPoint, - LayoutDeviceIntPoint* aOutTransformedPoint) -{ - MOZ_ASSERT(aOutTransformedPoint); - nsRefPtr apzc = GetTargetAPZC(aPoint, nullptr); - if (apzc && aOutTransformedPoint) { - Matrix4x4 transformToApzc = GetScreenToApzcTransform(apzc); - Matrix4x4 transformToGecko = GetApzcToGeckoTransform(apzc); - Matrix4x4 outTransform = transformToApzc * transformToGecko; - MOZ_ASSERT(outTransform.Is2D()); - *aOutTransformedPoint = TransformTo(outTransform, aPoint); - } -} - void APZCTreeManager::UpdateWheelTransaction(WidgetInputEvent& aEvent) { @@ -966,8 +971,11 @@ APZCTreeManager::ProcessEvent(WidgetInputEvent& aEvent, Matrix4x4 transformToApzc = GetScreenToApzcTransform(apzc); Matrix4x4 transformToGecko = GetApzcToGeckoTransform(apzc); Matrix4x4 outTransform = transformToApzc * transformToGecko; - MOZ_ASSERT(outTransform.Is2D()); - aEvent.refPoint = TransformTo(outTransform, aEvent.refPoint); + Maybe untransformedRefPoint = + UntransformTo(outTransform, aEvent.refPoint); + if (untransformedRefPoint) { + aEvent.refPoint = *untransformedRefPoint; + } } return result; } diff --git a/gfx/layers/apz/src/APZCTreeManager.h b/gfx/layers/apz/src/APZCTreeManager.h index e9594522b70e..3669a7997a88 100644 --- a/gfx/layers/apz/src/APZCTreeManager.h +++ b/gfx/layers/apz/src/APZCTreeManager.h @@ -209,15 +209,6 @@ public: ScrollableLayerGuid* aOutTargetGuid, uint64_t* aOutInputBlockId); - /** - * A helper for transforming coordinates to gecko coordinate space. - * - * @param aPoint point to transform - * @param aOutTransformedPoint resulting transformed point - */ - void TransformCoordinateToGecko(const ScreenIntPoint& aPoint, - LayoutDeviceIntPoint* aOutTransformedPoint); - /** * Kicks an animation to zoom to a rect. This may be either a zoom out or zoom * in. The actual animation is done on the compositor thread after being set diff --git a/gfx/layers/apz/src/AsyncPanZoomController.cpp b/gfx/layers/apz/src/AsyncPanZoomController.cpp index a30ce25a7a06..836dfb5987a8 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.cpp +++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp @@ -1422,13 +1422,15 @@ AsyncPanZoomController::ConvertToGecko(const ScreenIntPoint& aPoint, CSSPoint* a // NOTE: This isn't *quite* LayoutDevicePoint, we just don't have a name // for this coordinate space and it maps the closest to LayoutDevicePoint. - MOZ_ASSERT(transformScreenToGecko.Is2D()); - LayoutDevicePoint layoutPoint = TransformTo( + Maybe layoutPoint = UntransformTo( transformScreenToGecko, aPoint); + if (!layoutPoint) { + return false; + } { // scoped lock to access mFrameMetrics ReentrantMonitorAutoEnter lock(mMonitor); - *aOut = layoutPoint / mFrameMetrics.GetDevPixelsPerCSSPixel(); + *aOut = LayoutDevicePoint(*layoutPoint) / mFrameMetrics.GetDevPixelsPerCSSPixel(); } return true; } From bfaaa79619598d5f93c89216b08584fa582393e8 Mon Sep 17 00:00:00 2001 From: Mats Palmgren Date: Wed, 7 Oct 2015 00:54:51 +0200 Subject: [PATCH 102/228] Bug 790260 - Make CollectFloats remove the IS_PUSHED_FLOAT bit in case the float was collected from the PushedFloats list. r=roc --- layout/generic/nsBlockFrame.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index 15d614925d1d..d55b3befb424 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -2001,6 +2001,8 @@ nsBlockFrame::ReparentFloats(nsIFrame* aFirstFrame, nsBlockFrame* aOldParent, aOldParent->CollectFloats(aFirstFrame, list, aReparentSiblings); if (list.NotEmpty()) { for (nsIFrame* f : list) { + MOZ_ASSERT(!(f->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT), + "CollectFloats should've removed that bit"); ReparentFrame(f, aOldParent, this); } mFloats.AppendFrames(nullptr, list); @@ -4576,6 +4578,12 @@ nsBlockFrame::PushLines(nsBlockReflowState& aState, CollectFloats(overBegin->mFirstChild, floats, true); if (floats.NotEmpty()) { +#ifdef DEBUG + for (nsIFrame* f : floats) { + MOZ_ASSERT(!(f->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT), + "CollectFloats should've removed that bit"); + } +#endif // Push the floats onto the front of the overflow out-of-flows list nsAutoOOFFrameList oofs(this); oofs.mList.InsertFrames(nullptr, nullptr, floats); @@ -4705,6 +4713,12 @@ nsBlockFrame::DrainSelfOverflowList() // already ours. But we should put overflow floats back in mFloats. nsAutoOOFFrameList oofs(this); if (oofs.mList.NotEmpty()) { +#ifdef DEBUG + for (nsIFrame* f : oofs.mList) { + MOZ_ASSERT(!(f->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT), + "CollectFloats should've removed that bit"); + } +#endif // The overflow floats go after our regular floats. mFloats.AppendFrames(nullptr, oofs.mList); } @@ -7171,6 +7185,9 @@ nsBlockFrame::DoCollectFloats(nsIFrame* aFrame, nsFrameList& aList, nsLayoutUtils::GetFloatFromPlaceholder(aFrame) : nullptr; while (outOfFlowFrame && outOfFlowFrame->GetParent() == this) { RemoveFloat(outOfFlowFrame); + // Remove the IS_PUSHED_FLOAT bit, in case |outOfFlowFrame| came from + // the PushedFloats list. + outOfFlowFrame->RemoveStateBits(NS_FRAME_IS_PUSHED_FLOAT); aList.AppendFrame(nullptr, outOfFlowFrame); outOfFlowFrame = outOfFlowFrame->GetNextInFlow(); // FIXME: By not pulling floats whose parent is one of our From 778a4471544d61eb8f200e7db44059ea3013a1da Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Wed, 7 Oct 2015 00:54:51 +0200 Subject: [PATCH 103/228] Bug 790260 - Crashtest. --- layout/generic/crashtests/790260-1.html | 12 ++++++++++++ layout/generic/crashtests/crashtests.list | 1 + 2 files changed, 13 insertions(+) create mode 100644 layout/generic/crashtests/790260-1.html diff --git a/layout/generic/crashtests/790260-1.html b/layout/generic/crashtests/790260-1.html new file mode 100644 index 000000000000..f1536e3ed978 --- /dev/null +++ b/layout/generic/crashtests/790260-1.html @@ -0,0 +1,12 @@ + + + +
+
+ +
+
XYZ
+
+
+ + diff --git a/layout/generic/crashtests/crashtests.list b/layout/generic/crashtests/crashtests.list index f3fa2dd7520f..eeb6be44c2b4 100644 --- a/layout/generic/crashtests/crashtests.list +++ b/layout/generic/crashtests/crashtests.list @@ -495,6 +495,7 @@ load 783228.html skip-if(Android) load 784600.html load 785555.html load 786740-1.html +load 790260-1.html asserts(0-4) test-pref(font.size.inflation.emPerLine,15) load 791601.xhtml # 3 counts of bug 871327, 1 bug 367185 test-pref(font.size.inflation.minTwips,120) load 794693.html asserts-if(!Android,4) load 798020-1.html From 6795239dce699196e73540684440038d4bc73147 Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Tue, 6 Oct 2015 14:31:04 -0700 Subject: [PATCH 104/228] No bug. Remove some long obsolete files. r=woof! --HG-- extra : commitid : ColRK0WPSMO extra : rebase_source : 02581480dff3b99106096470a78d8cdf7666aff8 --- js/src/devtools/rootAnalysis/build.b2g | 4 ---- js/src/devtools/rootAnalysis/build.browser | 4 ---- js/src/devtools/rootAnalysis/build.shell | 7 ------- 3 files changed, 15 deletions(-) delete mode 100755 js/src/devtools/rootAnalysis/build.b2g delete mode 100755 js/src/devtools/rootAnalysis/build.browser delete mode 100755 js/src/devtools/rootAnalysis/build.shell diff --git a/js/src/devtools/rootAnalysis/build.b2g b/js/src/devtools/rootAnalysis/build.b2g deleted file mode 100755 index 902988d2496c..000000000000 --- a/js/src/devtools/rootAnalysis/build.b2g +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -cd $SOURCE -exec env MOZCONFIG=$SOURCE/mozconfig-b2g-ra ./mach build diff --git a/js/src/devtools/rootAnalysis/build.browser b/js/src/devtools/rootAnalysis/build.browser deleted file mode 100755 index da360bb68a64..000000000000 --- a/js/src/devtools/rootAnalysis/build.browser +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -cd $SOURCE -exec ./mach build diff --git a/js/src/devtools/rootAnalysis/build.shell b/js/src/devtools/rootAnalysis/build.shell deleted file mode 100755 index 46360bc0caa3..000000000000 --- a/js/src/devtools/rootAnalysis/build.shell +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -x - -mkdir $ANALYZED_OBJDIR -cd $ANALYZED_OBJDIR -$SOURCE/js/src/configure --enable-debug --enable-optimize --enable-root-analysis -# perl -i -pe 's!ccache ([gc])!$1!' "$TARGET_BUILDROOT/config/autoconf.mk" -make -j12 -s From 1eb9a856352181351e6c94af87135cfbbfb1ad2f Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Tue, 29 Sep 2015 13:39:37 -0700 Subject: [PATCH 105/228] Bug 1205887 - Verify that MOZILLA_VERSION was set correctly, r=glandium --HG-- extra : commitid : 3g91k2r7xzC extra : rebase_source : 2e49c764882e7234dddcdaea3273b7057ba12543 --- configure.in | 3 +++ js/src/configure.in | 3 +++ 2 files changed, 6 insertions(+) diff --git a/configure.in b/configure.in index 6ab4b7205986..36e438cf10d3 100644 --- a/configure.in +++ b/configure.in @@ -1862,6 +1862,9 @@ dnl ============================================================== MOZILLA_VERSION=`$PYTHON $srcdir/python/mozbuild/mozbuild/milestone.py --topsrcdir $srcdir` MOZILLA_UAVERSION=`$PYTHON $srcdir/python/mozbuild/mozbuild/milestone.py --topsrcdir $srcdir --uaversion` MOZILLA_SYMBOLVERSION=`$PYTHON $srcdir/python/mozbuild/mozbuild/milestone.py --topsrcdir $srcdir --symbolversion` +if test -z "$MOZILLA_VERSION"; then + AC_MSG_ERROR([failed to read version info from milestone file]) +fi dnl Get version of various core apps from the version files. FIREFOX_VERSION=`cat $_topsrcdir/browser/config/version.txt` diff --git a/js/src/configure.in b/js/src/configure.in index 99c6ada69b9c..15b2a1c73755 100644 --- a/js/src/configure.in +++ b/js/src/configure.in @@ -707,6 +707,9 @@ dnl ============================================================== MOZILLA_VERSION=`$PYTHON $srcdir/python/mozbuild/mozbuild/milestone.py --topsrcdir $srcdir` MOZILLA_UAVERSION=`$PYTHON $srcdir/python/mozbuild/mozbuild/milestone.py --topsrcdir $srcdir --uaversion` MOZILLA_SYMBOLVERSION=`$PYTHON $srcdir/python/mozbuild/mozbuild/milestone.py --topsrcdir $srcdir --symbolversion` +if test -z "$MOZILLA_VERSION"; then + AC_MSG_ERROR([failed to read version info from milestone file]) +fi AC_DEFINE_UNQUOTED(MOZILLA_VERSION,"$MOZILLA_VERSION") AC_DEFINE_UNQUOTED(MOZILLA_VERSION_U,$MOZILLA_VERSION) From b62b1c1bb877b243f582edf75b9844d62542a0f9 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Thu, 1 Oct 2015 12:50:13 -0400 Subject: [PATCH 106/228] Bug 1210302 - Part 1: Rename nsINetUtil.parseContentType() to parseResponseContentType(); r=mcmanus --- dom/apps/AppsUtils.jsm | 2 +- netwerk/base/nsINetUtil.idl | 8 +-- netwerk/base/nsIOService.cpp | 8 +-- netwerk/base/nsNetUtil.cpp | 4 +- netwerk/test/unit/test_parse_content_type.js | 54 ++++++++++---------- 5 files changed, 38 insertions(+), 38 deletions(-) diff --git a/dom/apps/AppsUtils.jsm b/dom/apps/AppsUtils.jsm index 23a2a070d890..8cd8bba7b8d6 100644 --- a/dom/apps/AppsUtils.jsm +++ b/dom/apps/AppsUtils.jsm @@ -507,7 +507,7 @@ this.AppsUtils = { let hadCharset = { }; let charset = { }; let netutil = Cc["@mozilla.org/network/util;1"].getService(Ci.nsINetUtil); - let contentType = netutil.parseContentType(aContentType, charset, hadCharset); + let contentType = netutil.parseResponseContentType(aContentType, charset, hadCharset); if (aInstallOrigin != aWebappOrigin && !(contentType == "application/x-web-app-manifest+json" || contentType == "application/manifest+json")) { diff --git a/netwerk/base/nsINetUtil.idl b/netwerk/base/nsINetUtil.idl index 157b556b1159..e2f259f09cac 100644 --- a/netwerk/base/nsINetUtil.idl +++ b/netwerk/base/nsINetUtil.idl @@ -11,7 +11,7 @@ interface nsIPrefBranch; /** * nsINetUtil provides various network-related utility methods. */ -[scriptable, uuid(885d6940-1001-46e7-92ec-d494a78d7784)] +[scriptable, uuid(ff0b3233-7ec5-4bf4-830f-6b2edaa53661)] interface nsINetUtil : nsISupports { /** @@ -24,9 +24,9 @@ interface nsINetUtil : nsISupports * @param [out] aHadCharset whether a charset was explicitly specified. * @return the MIME type specified in the header, in lower-case. */ - AUTF8String parseContentType(in AUTF8String aTypeHeader, - out AUTF8String aCharset, - out boolean aHadCharset); + AUTF8String parseResponseContentType(in AUTF8String aTypeHeader, + out AUTF8String aCharset, + out boolean aHadCharset); /** * Test whether the given URI's handler has the given protocol flags. diff --git a/netwerk/base/nsIOService.cpp b/netwerk/base/nsIOService.cpp index 910eeec7d55e..464c79adbba3 100644 --- a/netwerk/base/nsIOService.cpp +++ b/netwerk/base/nsIOService.cpp @@ -1507,10 +1507,10 @@ nsIOService::Observe(nsISupports *subject, // nsINetUtil interface NS_IMETHODIMP -nsIOService::ParseContentType(const nsACString &aTypeHeader, - nsACString &aCharset, - bool *aHadCharset, - nsACString &aContentType) +nsIOService::ParseResponseContentType(const nsACString &aTypeHeader, + nsACString &aCharset, + bool *aHadCharset, + nsACString &aContentType) { net_ParseContentType(aTypeHeader, aContentType, aCharset, aHadCharset); return NS_OK; diff --git a/netwerk/base/nsNetUtil.cpp b/netwerk/base/nsNetUtil.cpp index 207f6e408254..6b7eef1b1519 100644 --- a/netwerk/base/nsNetUtil.cpp +++ b/netwerk/base/nsNetUtil.cpp @@ -919,8 +919,8 @@ NS_ParseContentType(const nsACString &rawContentType, NS_ENSURE_SUCCESS(rv, rv); nsCString charset; bool hadCharset; - rv = util->ParseContentType(rawContentType, charset, &hadCharset, - contentType); + rv = util->ParseResponseContentType(rawContentType, charset, &hadCharset, + contentType); if (NS_SUCCEEDED(rv) && hadCharset) contentCharset = charset; return rv; diff --git a/netwerk/test/unit/test_parse_content_type.js b/netwerk/test/unit/test_parse_content_type.js index af83a5475371..7c0e414160a8 100644 --- a/netwerk/test/unit/test_parse_content_type.js +++ b/netwerk/test/unit/test_parse_content_type.js @@ -25,95 +25,95 @@ function run_test() { var netutil = Components.classes["@mozilla.org/network/util;1"] .getService(Components.interfaces.nsINetUtil); - type = netutil.parseContentType("text/html", charset, hadCharset); + type = netutil.parseResponseContentType("text/html", charset, hadCharset); check("text/html", "", false); - type = netutil.parseContentType("TEXT/HTML", charset, hadCharset); + type = netutil.parseResponseContentType("TEXT/HTML", charset, hadCharset); check("text/html", "", false); - type = netutil.parseContentType("text/html, text/html", charset, hadCharset); + type = netutil.parseResponseContentType("text/html, text/html", charset, hadCharset); check("text/html", "", false); - type = netutil.parseContentType("text/html, text/plain", + type = netutil.parseResponseContentType("text/html, text/plain", charset, hadCharset); check("text/plain", "", false); - type = netutil.parseContentType('text/html, ', charset, hadCharset); + type = netutil.parseResponseContentType('text/html, ', charset, hadCharset); check("text/html", "", false); - type = netutil.parseContentType('text/html, */*', charset, hadCharset); + type = netutil.parseResponseContentType('text/html, */*', charset, hadCharset); check("text/html", "", false); - type = netutil.parseContentType('text/html, foo', charset, hadCharset); + type = netutil.parseResponseContentType('text/html, foo', charset, hadCharset); check("text/html", "", false); - type = netutil.parseContentType("text/html; charset=ISO-8859-1", + type = netutil.parseResponseContentType("text/html; charset=ISO-8859-1", charset, hadCharset); check("text/html", "ISO-8859-1", true); - type = netutil.parseContentType('text/html; charset="ISO-8859-1"', + type = netutil.parseResponseContentType('text/html; charset="ISO-8859-1"', charset, hadCharset); check("text/html", "ISO-8859-1", true); - type = netutil.parseContentType("text/html; charset='ISO-8859-1'", + type = netutil.parseResponseContentType("text/html; charset='ISO-8859-1'", charset, hadCharset); check("text/html", "'ISO-8859-1'", true); - type = netutil.parseContentType("text/html; charset=\"ISO-8859-1\", text/html", + type = netutil.parseResponseContentType("text/html; charset=\"ISO-8859-1\", text/html", charset, hadCharset); check("text/html", "ISO-8859-1", true); - type = netutil.parseContentType("text/html; charset=\"ISO-8859-1\", text/html; charset=UTF8", + type = netutil.parseResponseContentType("text/html; charset=\"ISO-8859-1\", text/html; charset=UTF8", charset, hadCharset); check("text/html", "UTF8", true); - type = netutil.parseContentType("text/html; charset=ISO-8859-1, TEXT/HTML", charset, hadCharset); + type = netutil.parseResponseContentType("text/html; charset=ISO-8859-1, TEXT/HTML", charset, hadCharset); check("text/html", "ISO-8859-1", true); - type = netutil.parseContentType("text/html; charset=ISO-8859-1, TEXT/plain", charset, hadCharset); + type = netutil.parseResponseContentType("text/html; charset=ISO-8859-1, TEXT/plain", charset, hadCharset); check("text/plain", "", true); - type = netutil.parseContentType("text/plain, TEXT/HTML; charset=ISO-8859-1, text/html, TEXT/HTML", charset, hadCharset); + type = netutil.parseResponseContentType("text/plain, TEXT/HTML; charset=ISO-8859-1, text/html, TEXT/HTML", charset, hadCharset); check("text/html", "ISO-8859-1", true); - type = netutil.parseContentType('text/plain, TEXT/HTML; param="charset=UTF8"; charset="ISO-8859-1"; param2="charset=UTF16", text/html, TEXT/HTML', charset, hadCharset); + type = netutil.parseResponseContentType('text/plain, TEXT/HTML; param="charset=UTF8"; charset="ISO-8859-1"; param2="charset=UTF16", text/html, TEXT/HTML', charset, hadCharset); check("text/html", "ISO-8859-1", true); - type = netutil.parseContentType('text/plain, TEXT/HTML; param=charset=UTF8; charset="ISO-8859-1"; param2=charset=UTF16, text/html, TEXT/HTML', charset, hadCharset); + type = netutil.parseResponseContentType('text/plain, TEXT/HTML; param=charset=UTF8; charset="ISO-8859-1"; param2=charset=UTF16, text/html, TEXT/HTML', charset, hadCharset); check("text/html", "ISO-8859-1", true); - type = netutil.parseContentType("text/plain; param= , text/html", charset, hadCharset); + type = netutil.parseResponseContentType("text/plain; param= , text/html", charset, hadCharset); check("text/html", "", false); - type = netutil.parseContentType('text/plain; param=", text/html"', charset, hadCharset); + type = netutil.parseResponseContentType('text/plain; param=", text/html"', charset, hadCharset); check("text/plain", "", false); - type = netutil.parseContentType('text/plain; param=", \\" , text/html"', charset, hadCharset); + type = netutil.parseResponseContentType('text/plain; param=", \\" , text/html"', charset, hadCharset); check("text/plain", "", false); - type = netutil.parseContentType('text/plain; param=", \\" , text/html , "', charset, hadCharset); + type = netutil.parseResponseContentType('text/plain; param=", \\" , text/html , "', charset, hadCharset); check("text/plain", "", false); - type = netutil.parseContentType('text/plain param=", \\" , text/html , "', charset, hadCharset); + type = netutil.parseResponseContentType('text/plain param=", \\" , text/html , "', charset, hadCharset); check("text/plain", "", false); - type = netutil.parseContentType('text/plain charset=UTF8', charset, hadCharset); + type = netutil.parseResponseContentType('text/plain charset=UTF8', charset, hadCharset); check("text/plain", "", false); - type = netutil.parseContentType('text/plain, TEXT/HTML; param="charset=UTF8"; ; param2="charset=UTF16", text/html, TEXT/HTML', charset, hadCharset); + type = netutil.parseResponseContentType('text/plain, TEXT/HTML; param="charset=UTF8"; ; param2="charset=UTF16", text/html, TEXT/HTML', charset, hadCharset); check("text/html", "", false); // Bug 562915 - correctness: "\x" is "x" - type = netutil.parseContentType('text/plain; charset="UTF\\-8"', charset, hadCharset); + type = netutil.parseResponseContentType('text/plain; charset="UTF\\-8"', charset, hadCharset); check("text/plain", "UTF-8", true); // Bug 700589 // check that single quote doesn't confuse parsing of subsequent parameters - type = netutil.parseContentType("text/plain; x='; charset=\"UTF-8\"", charset, hadCharset); + type = netutil.parseResponseContentType("text/plain; x='; charset=\"UTF-8\"", charset, hadCharset); check("text/plain", "UTF-8", true); // check that single quotes do not get removed from extracted charset - type = netutil.parseContentType("text/plain; charset='UTF-8'", charset, hadCharset); + type = netutil.parseResponseContentType("text/plain; charset='UTF-8'", charset, hadCharset); check("text/plain", "'UTF-8'", true); } From c3300a106e23b133d66fe2ba10ea081db6bed736 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Thu, 1 Oct 2015 12:51:50 -0400 Subject: [PATCH 107/228] Bug 1210302 - Part 2: Rename NS_ParseContentType to NS_ParseResponseContentType; r=mcmanus,sicking --- dom/base/nsObjectLoadingContent.cpp | 2 +- modules/libjar/nsJARChannel.cpp | 4 ++-- netwerk/base/nsNetUtil.cpp | 6 +++--- netwerk/base/nsNetUtil.h | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/dom/base/nsObjectLoadingContent.cpp b/dom/base/nsObjectLoadingContent.cpp index 8e65e692a077..3340c35545ae 100644 --- a/dom/base/nsObjectLoadingContent.cpp +++ b/dom/base/nsObjectLoadingContent.cpp @@ -1881,7 +1881,7 @@ nsObjectLoadingContent::UpdateObjectParameters(bool aJavaURI) // end up trying to dispatch to a nsFrameLoader, which will complain that // it couldn't find a way to handle application/octet-stream nsAutoCString parsedMime, dummy; - NS_ParseContentType(newMime, parsedMime, dummy); + NS_ParseResponseContentType(newMime, parsedMime, dummy); if (!parsedMime.IsEmpty()) { mChannel->SetContentType(parsedMime); } diff --git a/modules/libjar/nsJARChannel.cpp b/modules/libjar/nsJARChannel.cpp index 3d080302ff1c..fbb5723c6c66 100644 --- a/modules/libjar/nsJARChannel.cpp +++ b/modules/libjar/nsJARChannel.cpp @@ -747,7 +747,7 @@ nsJARChannel::SetContentType(const nsACString &aContentType) // doing our guessing. So we don't care when this is being called. // mContentCharset is unchanged if not parsed - NS_ParseContentType(aContentType, mContentType, mContentCharset); + NS_ParseResponseContentType(aContentType, mContentType, mContentCharset); return NS_OK; } @@ -1180,7 +1180,7 @@ nsJARChannel::OnDownloadComplete(MemoryDownloader* aDownloader, header); nsAutoCString contentType; nsAutoCString charset; - NS_ParseContentType(header, contentType, charset); + NS_ParseResponseContentType(header, contentType, charset); nsAutoCString channelContentType; channel->GetContentType(channelContentType); mIsUnsafe = !(contentType.Equals(channelContentType) && diff --git a/netwerk/base/nsNetUtil.cpp b/netwerk/base/nsNetUtil.cpp index 6b7eef1b1519..8abab05ce215 100644 --- a/netwerk/base/nsNetUtil.cpp +++ b/netwerk/base/nsNetUtil.cpp @@ -909,9 +909,9 @@ NS_GetReferrerFromChannel(nsIChannel *channel, } nsresult -NS_ParseContentType(const nsACString &rawContentType, - nsCString &contentType, - nsCString &contentCharset) +NS_ParseResponseContentType(const nsACString &rawContentType, + nsCString &contentType, + nsCString &contentCharset) { // contentCharset is left untouched if not present in rawContentType nsresult rv; diff --git a/netwerk/base/nsNetUtil.h b/netwerk/base/nsNetUtil.h index 026e2f20bc6e..ebc71378aa75 100644 --- a/netwerk/base/nsNetUtil.h +++ b/netwerk/base/nsNetUtil.h @@ -488,9 +488,9 @@ nsresult NS_GetURLSpecFromDir(nsIFile *file, nsresult NS_GetReferrerFromChannel(nsIChannel *channel, nsIURI **referrer); -nsresult NS_ParseContentType(const nsACString &rawContentType, - nsCString &contentType, - nsCString &contentCharset); +nsresult NS_ParseResponseContentType(const nsACString &rawContentType, + nsCString &contentType, + nsCString &contentCharset); nsresult NS_ExtractCharsetFromContentType(const nsACString &rawContentType, nsCString &contentCharset, From 158253749db9f24a0947ac1403b8e1adb86f6f5c Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Thu, 1 Oct 2015 14:36:19 -0400 Subject: [PATCH 108/228] Bug 1210302 - Part 3: Add a NS_ParseRequestContentType API; r=mcmanus,sicking --- docshell/base/nsDocShell.cpp | 2 +- dom/base/Navigator.cpp | 4 +- dom/base/nsContentUtils.cpp | 2 +- dom/html/nsHTMLDocument.cpp | 2 +- dom/manifest/ImageObjectProcessor.jsm | 2 +- netwerk/base/nsINetUtil.idl | 20 +++++++-- netwerk/base/nsIOService.cpp | 11 +++++ netwerk/base/nsNetUtil.cpp | 18 ++++++++ netwerk/base/nsNetUtil.h | 4 ++ netwerk/base/nsURLHelper.cpp | 60 +++++++++++++++++++++++++-- netwerk/base/nsURLHelper.h | 32 ++++++++++---- 11 files changed, 136 insertions(+), 21 deletions(-) diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 209c242ae908..16cdac503c5c 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -13447,7 +13447,7 @@ nsDocShell::OnLinkClickSync(nsIContent* aContent, anchor->GetType(typeHint); NS_ConvertUTF16toUTF8 utf8Hint(typeHint); nsAutoCString type, dummy; - NS_ParseContentType(utf8Hint, type, dummy); + NS_ParseRequestContentType(utf8Hint, type, dummy); CopyUTF8toUTF16(type, typeHint); } diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp index 07099aae3fdd..4de628ca8f53 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -1312,9 +1312,9 @@ Navigator::SendBeacon(const nsAString& aUrl, rv = secMan->CheckSameOriginURI(documentURI, uri, false); bool crossOrigin = NS_FAILED(rv); nsAutoCString contentType, parsedCharset; - rv = NS_ParseContentType(mimeType, contentType, parsedCharset); + rv = NS_ParseRequestContentType(mimeType, contentType, parsedCharset); if (crossOrigin && - contentType.Length() > 0 && + mimeType.Length() > 0 && !contentType.Equals(APPLICATION_WWW_FORM_URLENCODED) && !contentType.Equals(MULTIPART_FORM_DATA) && !contentType.Equals(TEXT_PLAIN)) { diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index b2ba2b00a35e..a8a6f899d37b 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -7196,7 +7196,7 @@ nsContentUtils::IsAllowedNonCorsContentType(const nsACString& aHeaderValue) nsAutoCString contentType; nsAutoCString unused; - nsresult rv = NS_ParseContentType(aHeaderValue, contentType, unused); + nsresult rv = NS_ParseRequestContentType(aHeaderValue, contentType, unused); if (NS_FAILED(rv)) { return false; } diff --git a/dom/html/nsHTMLDocument.cpp b/dom/html/nsHTMLDocument.cpp index 2f29bddf61c6..80c136b7d110 100644 --- a/dom/html/nsHTMLDocument.cpp +++ b/dom/html/nsHTMLDocument.cpp @@ -1412,7 +1412,7 @@ nsHTMLDocument::Open(JSContext* cx, nsAutoString type; nsContentUtils::ASCIIToLower(aType, type); nsAutoCString actualType, dummy; - NS_ParseContentType(NS_ConvertUTF16toUTF8(type), actualType, dummy); + NS_ParseRequestContentType(NS_ConvertUTF16toUTF8(type), actualType, dummy); if (!actualType.EqualsLiteral("text/html") && !type.EqualsLiteral("replace")) { contentType.AssignLiteral("text/plain"); diff --git a/dom/manifest/ImageObjectProcessor.jsm b/dom/manifest/ImageObjectProcessor.jsm index 7f22fae9922a..33392048076e 100644 --- a/dom/manifest/ImageObjectProcessor.jsm +++ b/dom/manifest/ImageObjectProcessor.jsm @@ -92,7 +92,7 @@ ImageObjectProcessor.prototype.process = function( }; let value = extractor.extractValue(spec); if (value) { - value = netutil.parseContentType(value, charset, hadCharset); + value = netutil.parseRequestContentType(value, charset, hadCharset); } return value || undefined; } diff --git a/netwerk/base/nsINetUtil.idl b/netwerk/base/nsINetUtil.idl index e2f259f09cac..b9f1acbf968b 100644 --- a/netwerk/base/nsINetUtil.idl +++ b/netwerk/base/nsINetUtil.idl @@ -11,12 +11,26 @@ interface nsIPrefBranch; /** * nsINetUtil provides various network-related utility methods. */ -[scriptable, uuid(ff0b3233-7ec5-4bf4-830f-6b2edaa53661)] +[scriptable, uuid(fe2625ec-b884-4df1-b39c-9e830e47aa94)] interface nsINetUtil : nsISupports { /** - * Parse a content-type header and return the content type and - * charset (if any). + * Parse a content-type request header and return the content type + * and charset (if any). + * + * @param aTypeHeader the header string to parse + * @param [out] aCharset the charset parameter specified in the + * header, if any. + * @param [out] aHadCharset whether a charset was explicitly specified. + * @return the MIME type specified in the header, in lower-case. + */ + AUTF8String parseRequestContentType(in AUTF8String aTypeHeader, + out AUTF8String aCharset, + out boolean aHadCharset); + + /** + * Parse a content-type response header and return the content type + * and charset (if any). * * @param aTypeHeader the header string to parse * @param [out] aCharset the charset parameter specified in the diff --git a/netwerk/base/nsIOService.cpp b/netwerk/base/nsIOService.cpp index 464c79adbba3..2aa39b4cde12 100644 --- a/netwerk/base/nsIOService.cpp +++ b/netwerk/base/nsIOService.cpp @@ -1505,6 +1505,17 @@ nsIOService::Observe(nsISupports *subject, return NS_OK; } +// nsINetUtil interface +NS_IMETHODIMP +nsIOService::ParseRequestContentType(const nsACString &aTypeHeader, + nsACString &aCharset, + bool *aHadCharset, + nsACString &aContentType) +{ + net_ParseRequestContentType(aTypeHeader, aContentType, aCharset, aHadCharset); + return NS_OK; +} + // nsINetUtil interface NS_IMETHODIMP nsIOService::ParseResponseContentType(const nsACString &aTypeHeader, diff --git a/netwerk/base/nsNetUtil.cpp b/netwerk/base/nsNetUtil.cpp index 8abab05ce215..d4386ff0257a 100644 --- a/netwerk/base/nsNetUtil.cpp +++ b/netwerk/base/nsNetUtil.cpp @@ -908,6 +908,24 @@ NS_GetReferrerFromChannel(nsIChannel *channel, return rv; } +nsresult +NS_ParseRequestContentType(const nsACString &rawContentType, + nsCString &contentType, + nsCString &contentCharset) +{ + // contentCharset is left untouched if not present in rawContentType + nsresult rv; + nsCOMPtr util = do_GetNetUtil(&rv); + NS_ENSURE_SUCCESS(rv, rv); + nsCString charset; + bool hadCharset; + rv = util->ParseRequestContentType(rawContentType, charset, &hadCharset, + contentType); + if (NS_SUCCEEDED(rv) && hadCharset) + contentCharset = charset; + return rv; +} + nsresult NS_ParseResponseContentType(const nsACString &rawContentType, nsCString &contentType, diff --git a/netwerk/base/nsNetUtil.h b/netwerk/base/nsNetUtil.h index ebc71378aa75..1bbbd664f2a7 100644 --- a/netwerk/base/nsNetUtil.h +++ b/netwerk/base/nsNetUtil.h @@ -488,6 +488,10 @@ nsresult NS_GetURLSpecFromDir(nsIFile *file, nsresult NS_GetReferrerFromChannel(nsIChannel *channel, nsIURI **referrer); +nsresult NS_ParseRequestContentType(const nsACString &rawContentType, + nsCString &contentType, + nsCString &contentCharset); + nsresult NS_ParseResponseContentType(const nsACString &rawContentType, nsCString &contentType, nsCString &contentCharset); diff --git a/netwerk/base/nsURLHelper.cpp b/netwerk/base/nsURLHelper.cpp index f68183e96504..69598dbe7d36 100644 --- a/netwerk/base/nsURLHelper.cpp +++ b/netwerk/base/nsURLHelper.cpp @@ -828,7 +828,8 @@ net_ParseMediaType(const nsACString &aMediaTypeStr, int32_t aOffset, bool *aHadCharset, int32_t *aCharsetStart, - int32_t *aCharsetEnd) + int32_t *aCharsetEnd, + bool aStrict) { const nsCString& flatStr = PromiseFlatCString(aMediaTypeStr); const char* start = flatStr.get(); @@ -845,6 +846,8 @@ net_ParseMediaType(const nsACString &aMediaTypeStr, int32_t charsetParamStart = 0; int32_t charsetParamEnd = 0; + uint32_t consumed = typeEnd - type; + // Iterate over parameters bool typeHasCharset = false; uint32_t paramStart = flatStr.FindChar(';', typeEnd - start); @@ -868,6 +871,7 @@ net_ParseMediaType(const nsACString &aMediaTypeStr, charsetParamEnd = curParamEnd; } + consumed = curParamEnd; curParamStart = curParamEnd + 1; } while (curParamStart < flatStr.Length()); } @@ -897,8 +901,10 @@ net_ParseMediaType(const nsACString &aMediaTypeStr, // some servers give junk after the charset parameter, which may // include a comma, so this check makes us a bit more tolerant. - if (type != typeEnd && strncmp(type, "*/*", typeEnd - type) != 0 && - memchr(type, '/', typeEnd - type) != nullptr) { + if (type != typeEnd && + memchr(type, '/', typeEnd - type) != nullptr && + (aStrict ? (net_FindCharNotInSet(start + consumed, end, HTTP_LWS) == end) : + (strncmp(type, "*/*", typeEnd - type) != 0))) { // Common case here is that aContentType is empty bool eq = !aContentType.IsEmpty() && aContentType.Equals(Substring(type, typeEnd), @@ -1005,13 +1011,59 @@ net_ParseContentType(const nsACString &aHeaderStr, net_ParseMediaType(Substring(flatStr, curTypeStart, curTypeEnd - curTypeStart), aContentType, aContentCharset, curTypeStart, - aHadCharset, aCharsetStart, aCharsetEnd); + aHadCharset, aCharsetStart, aCharsetEnd, false); // And let's move on to the next media-type curTypeStart = curTypeEnd + 1; } while (curTypeStart < flatStr.Length()); } +void +net_ParseRequestContentType(const nsACString &aHeaderStr, + nsACString &aContentType, + nsACString &aContentCharset, + bool *aHadCharset) +{ + // + // Augmented BNF (from RFC 7231 section 3.1.1.1): + // + // media-type = type "/" subtype *( OWS ";" OWS parameter ) + // type = token + // subtype = token + // parameter = token "=" ( token / quoted-string ) + // + // Examples: + // + // text/html + // text/html; charset=ISO-8859-1 + // text/html; charset="ISO-8859-1" + // application/octet-stream + // + + aContentType.Truncate(); + aContentCharset.Truncate(); + *aHadCharset = false; + const nsCString& flatStr = PromiseFlatCString(aHeaderStr); + + // At this point curTypeEnd points to the spot where the media-type + // starting at curTypeEnd ends. Time to parse that! + nsAutoCString contentType, contentCharset; + bool hadCharset = false; + int32_t dummy1, dummy2; + uint32_t typeEnd = net_FindMediaDelimiter(flatStr, 0, ','); + if (typeEnd != flatStr.Length()) { + // We have some stuff left at the end, so this is not a valid + // request Content-Type header. + return; + } + net_ParseMediaType(flatStr, contentType, contentCharset, 0, + &hadCharset, &dummy1, &dummy2, true); + + aContentType = contentType; + aContentCharset = contentCharset; + *aHadCharset = hadCharset; +} + bool net_IsValidHostName(const nsCSubstring &host) { diff --git a/netwerk/base/nsURLHelper.h b/netwerk/base/nsURLHelper.h index 94ee2b184190..bc4dacf36524 100644 --- a/netwerk/base/nsURLHelper.h +++ b/netwerk/base/nsURLHelper.h @@ -165,6 +165,22 @@ char * net_FindCharNotInSet(const char *str, const char *end, const char *set); */ char * net_RFindCharNotInSet(const char *str, const char *end, const char *set); +/** + * Parses a content-type header and returns the content type and + * charset (if any). aCharset is not modified if no charset is + * specified in anywhere in aHeaderStr. In that case (no charset + * specified), aHadCharset is set to false. Otherwise, it's set to + * true. Note that aContentCharset can be empty even if aHadCharset + * is true. + * + * This parsing is suitable for HTTP request. Use net_ParseContentType + * for parsing this header in HTTP responses. + */ +void net_ParseRequestContentType(const nsACString &aHeaderStr, + nsACString &aContentType, + nsACString &aContentCharset, + bool* aHadCharset); + /** * Parses a content-type header and returns the content type and * charset (if any). aCharset is not modified if no charset is @@ -174,9 +190,9 @@ char * net_RFindCharNotInSet(const char *str, const char *end, const char *set); * is true. */ void net_ParseContentType(const nsACString &aHeaderStr, - nsACString &aContentType, - nsACString &aContentCharset, - bool* aHadCharset); + nsACString &aContentType, + nsACString &aContentCharset, + bool* aHadCharset); /** * As above, but also returns the start and end indexes for the charset * parameter in aHeaderStr. These are indices for the entire parameter, NOT @@ -187,11 +203,11 @@ void net_ParseContentType(const nsACString &aHeaderStr, * *aCharsetStart is nonnegative; this corresponds to charset="". */ void net_ParseContentType(const nsACString &aHeaderStr, - nsACString &aContentType, - nsACString &aContentCharset, - bool *aHadCharset, - int32_t *aCharsetStart, - int32_t *aCharsetEnd); + nsACString &aContentType, + nsACString &aContentCharset, + bool *aHadCharset, + int32_t *aCharsetStart, + int32_t *aCharsetEnd); /* inline versions */ From dd2362b62314d98bc059058da8a8817b994b538a Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Tue, 6 Oct 2015 17:51:12 -0700 Subject: [PATCH 109/228] Backed out changeset e58169d5f96a (bug 1204800) for flame-kk build failures --- .../aries-dogfood/releng-aries-dogfood.tt | 16 ---------- .../aries-spark-ota/releng-aries-spark-ota.tt | 16 ---------- b2g/config/aries/config.json | 2 +- b2g/config/aries/releng-aries.tt | 16 +++++----- b2g/config/dolphin-512/releng-dolphin-512.tt | 16 ---------- b2g/config/dolphin/releng-dolphin.tt | 9 +----- .../flame-kk-ota/releng-flame-kk-ota.tt | 16 ---------- b2g/config/flame-kk/config.json | 2 +- b2g/config/flame-kk/releng-flame-kk.tt | 16 +++++----- b2g/config/flame/config.json | 2 +- b2g/config/flame/releng-flame.tt | 14 ++++----- b2g/config/nexus-4-kk/releng-mako.tt | 28 ++++++++++++----- b2g/config/nexus-4/releng-mako.tt | 30 +++++++++++++------ b2g/config/nexus-5-l/releng-nexus5.tt | 12 ++------ .../scripts/phone-builder/pre-build.sh | 3 -- .../tasks/builds/b2g_aries_spark_debug.yml | 1 - .../tasks/builds/b2g_aries_spark_dogfood.yml | 1 - .../tasks/builds/b2g_aries_spark_eng.yml | 1 - .../tasks/builds/b2g_aries_spark_opt.yml | 1 - .../builds/b2g_aries_spark_ota_debug.yml | 1 - .../tasks/builds/b2g_aries_spark_ota_opt.yml | 2 +- .../tasks/builds/b2g_dolphin_512_eng.yml | 2 +- .../tasks/builds/b2g_dolphin_512_opt.yml | 1 - .../tasks/builds/b2g_dolphin_eng.yml | 1 - .../tasks/builds/b2g_dolphin_opt.yml | 2 +- .../tasks/builds/b2g_flame_kk_debug.yml | 1 - .../tasks/builds/b2g_flame_kk_eng.yml | 1 - .../tasks/builds/b2g_flame_kk_opt.yml | 1 - .../tasks/builds/b2g_flame_kk_ota_debug.yml | 1 - .../tasks/builds/b2g_flame_kk_ota_opt.yml | 1 - .../tasks/builds/b2g_flame_kk_spark_eng.yml | 1 - .../tasks/builds/b2g_nexus_4_eng.yml | 1 - .../tasks/builds/b2g_nexus_4_kk_eng.yml | 1 - .../tasks/builds/b2g_nexus_4_kk_user.yml | 1 - .../tasks/builds/b2g_nexus_4_user.yml | 1 - .../tasks/builds/b2g_nexus_5l_eng.yml | 1 - .../tasks/builds/b2g_nexus_5l_user.yml | 1 - .../tasks/builds/b2g_phone_base.yml | 4 --- testing/taskcluster/tasks/phone_build.yml | 2 -- 39 files changed, 72 insertions(+), 157 deletions(-) delete mode 100644 b2g/config/aries-dogfood/releng-aries-dogfood.tt delete mode 100644 b2g/config/aries-spark-ota/releng-aries-spark-ota.tt delete mode 100644 b2g/config/dolphin-512/releng-dolphin-512.tt delete mode 100644 b2g/config/flame-kk-ota/releng-flame-kk-ota.tt diff --git a/b2g/config/aries-dogfood/releng-aries-dogfood.tt b/b2g/config/aries-dogfood/releng-aries-dogfood.tt deleted file mode 100644 index 4f97e6b2db87..000000000000 --- a/b2g/config/aries-dogfood/releng-aries-dogfood.tt +++ /dev/null @@ -1,16 +0,0 @@ -[ -{ -"size": 80458572, -"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad", -"algorithm": "sha512", -"filename": "gcc.tar.xz", -"unpack": true -}, -{ -"size": 12057960, -"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e", -"algorithm": "sha512", -"filename": "gtk3.tar.xz", -"unpack": true -} -] diff --git a/b2g/config/aries-spark-ota/releng-aries-spark-ota.tt b/b2g/config/aries-spark-ota/releng-aries-spark-ota.tt deleted file mode 100644 index 4f97e6b2db87..000000000000 --- a/b2g/config/aries-spark-ota/releng-aries-spark-ota.tt +++ /dev/null @@ -1,16 +0,0 @@ -[ -{ -"size": 80458572, -"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad", -"algorithm": "sha512", -"filename": "gcc.tar.xz", -"unpack": true -}, -{ -"size": 12057960, -"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e", -"algorithm": "sha512", -"filename": "gtk3.tar.xz", -"unpack": true -} -] diff --git a/b2g/config/aries/config.json b/b2g/config/aries/config.json index a5f97937bb48..93683c532cfe 100644 --- a/b2g/config/aries/config.json +++ b/b2g/config/aries/config.json @@ -39,7 +39,7 @@ }, "b2g_manifest": "aries.xml", "b2g_manifest_intree": true, - "additional_source_tarballs": [], + "additional_source_tarballs": ["backup-aries.tar.xz"], "gecko_l10n_root": "https://hg.mozilla.org/l10n-central", "gaia": { "l10n": { diff --git a/b2g/config/aries/releng-aries.tt b/b2g/config/aries/releng-aries.tt index 4f97e6b2db87..74b32b01f17b 100644 --- a/b2g/config/aries/releng-aries.tt +++ b/b2g/config/aries/releng-aries.tt @@ -1,16 +1,16 @@ [ { +"size": 135359412, +"digest": "45e677c9606cc4eec44ef4761df47ff431df1ffad17a5c6d21ce700a1c47f79e87a4aa9f30ae47ff060bd64f5b775d995780d88211f9a759ffa0d076beb4816b", +"algorithm": "sha512", +"filename": "backup-aries.tar.xz", +"comment": "v18D" +}, +{ "size": 80458572, "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad", "algorithm": "sha512", "filename": "gcc.tar.xz", -"unpack": true -}, -{ -"size": 12057960, -"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e", -"algorithm": "sha512", -"filename": "gtk3.tar.xz", -"unpack": true +"unpack": "True" } ] diff --git a/b2g/config/dolphin-512/releng-dolphin-512.tt b/b2g/config/dolphin-512/releng-dolphin-512.tt deleted file mode 100644 index 4f97e6b2db87..000000000000 --- a/b2g/config/dolphin-512/releng-dolphin-512.tt +++ /dev/null @@ -1,16 +0,0 @@ -[ -{ -"size": 80458572, -"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad", -"algorithm": "sha512", -"filename": "gcc.tar.xz", -"unpack": true -}, -{ -"size": 12057960, -"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e", -"algorithm": "sha512", -"filename": "gtk3.tar.xz", -"unpack": true -} -] diff --git a/b2g/config/dolphin/releng-dolphin.tt b/b2g/config/dolphin/releng-dolphin.tt index 4f97e6b2db87..1af12208b9da 100644 --- a/b2g/config/dolphin/releng-dolphin.tt +++ b/b2g/config/dolphin/releng-dolphin.tt @@ -4,13 +4,6 @@ "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad", "algorithm": "sha512", "filename": "gcc.tar.xz", -"unpack": true -}, -{ -"size": 12057960, -"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e", -"algorithm": "sha512", -"filename": "gtk3.tar.xz", -"unpack": true +"unpack": "True" } ] diff --git a/b2g/config/flame-kk-ota/releng-flame-kk-ota.tt b/b2g/config/flame-kk-ota/releng-flame-kk-ota.tt deleted file mode 100644 index 4f97e6b2db87..000000000000 --- a/b2g/config/flame-kk-ota/releng-flame-kk-ota.tt +++ /dev/null @@ -1,16 +0,0 @@ -[ -{ -"size": 80458572, -"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad", -"algorithm": "sha512", -"filename": "gcc.tar.xz", -"unpack": true -}, -{ -"size": 12057960, -"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e", -"algorithm": "sha512", -"filename": "gtk3.tar.xz", -"unpack": true -} -] diff --git a/b2g/config/flame-kk/config.json b/b2g/config/flame-kk/config.json index 271945e1f0e3..15cfa1a584db 100644 --- a/b2g/config/flame-kk/config.json +++ b/b2g/config/flame-kk/config.json @@ -41,7 +41,7 @@ }, "b2g_manifest": "flame-kk.xml", "b2g_manifest_intree": true, - "additional_source_tarballs": [], + "additional_source_tarballs": ["backup-flame.tar.xz"], "gecko_l10n_root": "https://hg.mozilla.org/l10n-central", "gaia": { "l10n": { diff --git a/b2g/config/flame-kk/releng-flame-kk.tt b/b2g/config/flame-kk/releng-flame-kk.tt index 4f97e6b2db87..d0e0c584aa85 100644 --- a/b2g/config/flame-kk/releng-flame-kk.tt +++ b/b2g/config/flame-kk/releng-flame-kk.tt @@ -1,16 +1,16 @@ [ { +"size": 135359412, +"digest": "45e677c9606cc4eec44ef4761df47ff431df1ffad17a5c6d21ce700a1c47f79e87a4aa9f30ae47ff060bd64f5b775d995780d88211f9a759ffa0d076beb4816b", +"algorithm": "sha512", +"filename": "backup-flame.tar.xz", +"comment": "v18D" +}, +{ "size": 80458572, "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad", "algorithm": "sha512", "filename": "gcc.tar.xz", -"unpack": true -}, -{ -"size": 12057960, -"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e", -"algorithm": "sha512", -"filename": "gtk3.tar.xz", -"unpack": true +"unpack": "True" } ] diff --git a/b2g/config/flame/config.json b/b2g/config/flame/config.json index 71515cd32c93..6757312a0834 100644 --- a/b2g/config/flame/config.json +++ b/b2g/config/flame/config.json @@ -40,7 +40,7 @@ }, "b2g_manifest": "flame.xml", "b2g_manifest_intree": true, - "additional_source_tarballs": [], + "additional_source_tarballs": ["backup-flame.tar.xz"], "gecko_l10n_root": "https://hg.mozilla.org/l10n-central", "gaia": { "l10n": { diff --git a/b2g/config/flame/releng-flame.tt b/b2g/config/flame/releng-flame.tt index 4f97e6b2db87..65f9871b6796 100644 --- a/b2g/config/flame/releng-flame.tt +++ b/b2g/config/flame/releng-flame.tt @@ -1,16 +1,14 @@ [ +{"size": 149922032, +"digest": "8d1a71552ffee561e93b5b3f1bb47866592ab958f908007c75561156430eb1b85a265bfc4dc2038e58dda0264daa9854877a84ef3b591c9ac2f1ab97c098e61e", +"filename": "backup-flame.tar.xz", +"algorithm": "sha512" +}, { "size": 80458572, "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad", "algorithm": "sha512", "filename": "gcc.tar.xz", -"unpack": true -}, -{ -"size": 12057960, -"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e", -"algorithm": "sha512", -"filename": "gtk3.tar.xz", -"unpack": true +"unpack": "True" } ] diff --git a/b2g/config/nexus-4-kk/releng-mako.tt b/b2g/config/nexus-4-kk/releng-mako.tt index 35a9d3a879ed..bd916f022cb3 100644 --- a/b2g/config/nexus-4-kk/releng-mako.tt +++ b/b2g/config/nexus-4-kk/releng-mako.tt @@ -1,16 +1,28 @@ -[{ +[ +{ +"size": i13096, +"digest": "674475286c1639379079dca3cd14bfb9cc2a7e23733cd0f96e20296b2ee6dc0cdb9fccdc8635bef0475add156e085c17b946ec2c4254c83d3bef95d027e03537", +"algorithm": "sha512", +"filename": "broadcom-mako-kot49h-18b58457.tgz" +}, +{ +"size": 17661109, +"digest": "a5fcd2fda9fec1d24bb15e160f0ac2627a2b65e411f737c6cac48e777847c5a9eef3251af7deb535af89643a05e9889b857d1f60bf11df18fa270fd7b2db16db", +"algorithm": "sha512", +"filename": "qcom-mako-kot49h-e7a74920.tgz" +}, +{ +"size": 163277, +"digest": "e58aad76e6395a1a82fe886783842c4676c12d065e2f65bce6ce19cab2488be767aaea27fa2f46f48a0bf8d9714a6b453b474d2f9df5de158c49e6cbde0a359e", +"algorithm": "sha512", +"filename": "lge-mako-kot49h-f59c98be.tgz" +}, +{ "size": 80458572, "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad", "algorithm": "sha512", "filename": "gcc.tar.xz", "unpack": "True" -}, -{ -"size": 12057960, -"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e", -"algorithm": "sha512", -"filename": "gtk3.tar.xz", -"unpack": true } ] diff --git a/b2g/config/nexus-4/releng-mako.tt b/b2g/config/nexus-4/releng-mako.tt index 608c2521e92c..f83b6888fd46 100644 --- a/b2g/config/nexus-4/releng-mako.tt +++ b/b2g/config/nexus-4/releng-mako.tt @@ -1,16 +1,28 @@ [ { +"size": 13111, +"digest": "09373556ddb4325897b9e008184228f9088b4c8c22bacf4fa2d39793ecfd264316ad69c2bc8082229ad7fdb80f89154c7b995a60f9b18beb1847e7111e7e69b2", +"algorithm": "sha512", +"filename": "broadcom-mako-jwr66v-cbde0d61.tgz" +}, +{ +"size": 12658359, +"digest": "2483df1a949df53d02ca33a87731cedd8f7cd07114d723bde1addf63fd71154c23b6f11f64f390b9849121725fb53a402db8df2f96a3673ec52416f45260f79d", +"algorithm": "sha512", +"filename": "qcom-mako-jwr66v-30ef957c.tgz" +}, +{ +"size": 378532, +"digest": "27aced8feb0e757d61df37839e62410ff30a059cfa8f04897d29ab74b787c765313acf904b1f9cf311c3e682883514df7da54197665251ef9b8bdad6bd0f62c5", +"algorithm": "sha512", +"filename": "lge-mako-jwr66v-985845e4.tgz" +}, +{ "size": 80458572, "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad", "algorithm": "sha512", "filename": "gcc.tar.xz", -"unpack": true -}, -{ -"size": 12057960, -"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e", -"algorithm": "sha512", -"filename": "gtk3.tar.xz", -"unpack": true +"unpack": "True" } -] \ No newline at end of file +] + diff --git a/b2g/config/nexus-5-l/releng-nexus5.tt b/b2g/config/nexus-5-l/releng-nexus5.tt index 5e02a2162c22..c29e812bbb41 100644 --- a/b2g/config/nexus-5-l/releng-nexus5.tt +++ b/b2g/config/nexus-5-l/releng-nexus5.tt @@ -3,13 +3,5 @@ "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad", "algorithm": "sha512", "filename": "gcc.tar.xz", -"unpack": true -}, -{ -"size": 12057960, -"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e", -"algorithm": "sha512", -"filename": "gtk3.tar.xz", -"unpack": true -} -] +"unpack": "True" +}] diff --git a/testing/taskcluster/scripts/phone-builder/pre-build.sh b/testing/taskcluster/scripts/phone-builder/pre-build.sh index ac44b1ce2d09..000e7ef444b6 100755 --- a/testing/taskcluster/scripts/phone-builder/pre-build.sh +++ b/testing/taskcluster/scripts/phone-builder/pre-build.sh @@ -26,9 +26,6 @@ tc-vcs repo-checkout $WORKSPACE/B2G https://git.mozilla.org/b2g/B2G.git $MANIFES rm -f $WORKSPACE/B2G/gecko ln -s $WORKSPACE/gecko $WORKSPACE/B2G/gecko -### Install package dependencies -. ../builder/install-packages.sh $WORKSPACE/gecko - debug_flag="" if [ 0$B2G_DEBUG -ne 0 ]; then debug_flag='--debug' diff --git a/testing/taskcluster/tasks/builds/b2g_aries_spark_debug.yml b/testing/taskcluster/tasks/builds/b2g_aries_spark_debug.yml index b3e946cc5fc7..0c751a811aa1 100644 --- a/testing/taskcluster/tasks/builds/b2g_aries_spark_debug.yml +++ b/testing/taskcluster/tasks/builds/b2g_aries_spark_debug.yml @@ -22,7 +22,6 @@ task: GAIA_OPTIMIZE: '1' B2G_SYSTEM_APPS: '1' MOZHARNESS_CONFIG: b2g/taskcluster-spark.py - TOOLTOOL_MANIFEST: 'b2g/config/aries/releng-aries.tt' command: - > checkout-gecko workspace && diff --git a/testing/taskcluster/tasks/builds/b2g_aries_spark_dogfood.yml b/testing/taskcluster/tasks/builds/b2g_aries_spark_dogfood.yml index 5e8ef782be65..99a859487897 100644 --- a/testing/taskcluster/tasks/builds/b2g_aries_spark_dogfood.yml +++ b/testing/taskcluster/tasks/builds/b2g_aries_spark_dogfood.yml @@ -18,7 +18,6 @@ task: DOGFOOD: 1 HARDWARE_COMPOSER: 0 MOZHARNESS_CONFIG: b2g/taskcluster-spark-dogfood.py - TOOLTOOL_MANIFEST: 'b2g/config/aries-dogfood/releng-aries-dogfood.tt' extra: treeherderEnv: - production diff --git a/testing/taskcluster/tasks/builds/b2g_aries_spark_eng.yml b/testing/taskcluster/tasks/builds/b2g_aries_spark_eng.yml index f138a3475740..7c3e71fc05c4 100644 --- a/testing/taskcluster/tasks/builds/b2g_aries_spark_eng.yml +++ b/testing/taskcluster/tasks/builds/b2g_aries_spark_eng.yml @@ -17,7 +17,6 @@ task: env: TARGET: 'aries' MOZHARNESS_CONFIG: b2g/taskcluster-spark.py - TOOLTOOL_MANIFEST: 'b2g/config/aries/releng-aries.tt' extra: treeherderEnv: - production diff --git a/testing/taskcluster/tasks/builds/b2g_aries_spark_opt.yml b/testing/taskcluster/tasks/builds/b2g_aries_spark_opt.yml index c2aa962fa5c5..9207c05a7e62 100644 --- a/testing/taskcluster/tasks/builds/b2g_aries_spark_opt.yml +++ b/testing/taskcluster/tasks/builds/b2g_aries_spark_opt.yml @@ -22,7 +22,6 @@ task: GAIA_OPTIMIZE: '1' B2G_SYSTEM_APPS: '1' MOZHARNESS_CONFIG: b2g/taskcluster-spark.py - TOOLTOOL_MANIFEST: 'b2g/config/aries/releng-aries.tt' command: - > checkout-gecko workspace && diff --git a/testing/taskcluster/tasks/builds/b2g_aries_spark_ota_debug.yml b/testing/taskcluster/tasks/builds/b2g_aries_spark_ota_debug.yml index d83ce13af5b2..a62627ad4e63 100644 --- a/testing/taskcluster/tasks/builds/b2g_aries_spark_ota_debug.yml +++ b/testing/taskcluster/tasks/builds/b2g_aries_spark_ota_debug.yml @@ -16,5 +16,4 @@ task: env: VARIANT: userdebug B2G_DEBUG: 0 - TOOLTOOL_MANIFEST: 'b2g/config/aries-spark-ota/releng-aries-spark-ota.tt' diff --git a/testing/taskcluster/tasks/builds/b2g_aries_spark_ota_opt.yml b/testing/taskcluster/tasks/builds/b2g_aries_spark_ota_opt.yml index 19c5006e1c29..c7c63437386c 100644 --- a/testing/taskcluster/tasks/builds/b2g_aries_spark_ota_opt.yml +++ b/testing/taskcluster/tasks/builds/b2g_aries_spark_ota_opt.yml @@ -15,4 +15,4 @@ task: build-aries-spark-ota-user-objdir-gecko-{{project}}: /home/worker/objdir-gecko env: VARIANT: user - TOOLTOOL_MANIFEST: 'b2g/config/aries-spark-ota/releng-aries-spark-ota.tt' + diff --git a/testing/taskcluster/tasks/builds/b2g_dolphin_512_eng.yml b/testing/taskcluster/tasks/builds/b2g_dolphin_512_eng.yml index 46ff4a08dbc6..044de79850e6 100644 --- a/testing/taskcluster/tasks/builds/b2g_dolphin_512_eng.yml +++ b/testing/taskcluster/tasks/builds/b2g_dolphin_512_eng.yml @@ -20,4 +20,4 @@ task: env: TARGET: 'dolphin-512' VARIANT: eng - TOOLTOOL_MANIFEST: 'b2g/config/dolphin-512/releng-dolphin-512.tt' + diff --git a/testing/taskcluster/tasks/builds/b2g_dolphin_512_opt.yml b/testing/taskcluster/tasks/builds/b2g_dolphin_512_opt.yml index e1d4489211de..e51e0ce2a692 100644 --- a/testing/taskcluster/tasks/builds/b2g_dolphin_512_opt.yml +++ b/testing/taskcluster/tasks/builds/b2g_dolphin_512_opt.yml @@ -18,4 +18,3 @@ task: build-dolphin-512-opt: /home/worker/workspace env: TARGET: 'dolphin-512' - TOOLTOOL_MANIFEST: 'b2g/config/dolphin-512/releng-dolphin-512.tt' \ No newline at end of file diff --git a/testing/taskcluster/tasks/builds/b2g_dolphin_eng.yml b/testing/taskcluster/tasks/builds/b2g_dolphin_eng.yml index 000d0e25c5e3..ae1aa3c940fc 100644 --- a/testing/taskcluster/tasks/builds/b2g_dolphin_eng.yml +++ b/testing/taskcluster/tasks/builds/b2g_dolphin_eng.yml @@ -20,4 +20,3 @@ task: env: TARGET: 'dolphin' VARIANT: eng - TOOLTOOL_MANIFEST: 'b2g/config/dolphin/releng-dolphin.tt' \ No newline at end of file diff --git a/testing/taskcluster/tasks/builds/b2g_dolphin_opt.yml b/testing/taskcluster/tasks/builds/b2g_dolphin_opt.yml index ec623766182a..a6a45d4892d1 100644 --- a/testing/taskcluster/tasks/builds/b2g_dolphin_opt.yml +++ b/testing/taskcluster/tasks/builds/b2g_dolphin_opt.yml @@ -18,4 +18,4 @@ task: build-dolphin-opt: /home/worker/workspace env: TARGET: 'dolphin' - TOOLTOOL_MANIFEST: 'b2g/config/dolphin/releng-dolphin.tt' + diff --git a/testing/taskcluster/tasks/builds/b2g_flame_kk_debug.yml b/testing/taskcluster/tasks/builds/b2g_flame_kk_debug.yml index 61c9ce96308b..42fc7744d197 100644 --- a/testing/taskcluster/tasks/builds/b2g_flame_kk_debug.yml +++ b/testing/taskcluster/tasks/builds/b2g_flame_kk_debug.yml @@ -19,7 +19,6 @@ task: TARGET: 'flame-kk' DEBUG: 0 VARIANT: userdebug - TOOLTOOL_MANIFEST: 'b2g/config/flame-kk/releng-flame-kk.tt' command: - > checkout-gecko workspace && diff --git a/testing/taskcluster/tasks/builds/b2g_flame_kk_eng.yml b/testing/taskcluster/tasks/builds/b2g_flame_kk_eng.yml index 1b1c7452c173..7d8f1cfe8cff 100644 --- a/testing/taskcluster/tasks/builds/b2g_flame_kk_eng.yml +++ b/testing/taskcluster/tasks/builds/b2g_flame_kk_eng.yml @@ -16,7 +16,6 @@ task: build-flame-kk-eng-objdir-gecko-{{project}}: /home/worker/objdir-gecko env: TARGET: 'flame-kk' - TOOLTOOL_MANIFEST: 'b2g/config/flame-kk/releng-flame-kk.tt' extra: treeherderEnv: - production diff --git a/testing/taskcluster/tasks/builds/b2g_flame_kk_opt.yml b/testing/taskcluster/tasks/builds/b2g_flame_kk_opt.yml index 0e06f93d1733..e007d5bbcc63 100644 --- a/testing/taskcluster/tasks/builds/b2g_flame_kk_opt.yml +++ b/testing/taskcluster/tasks/builds/b2g_flame_kk_opt.yml @@ -18,7 +18,6 @@ task: env: TARGET: 'flame-kk' DEBUG: 0 - TOOLTOOL_MANIFEST: 'b2g/config/flame-kk/releng-flame-kk.tt' command: - > checkout-gecko workspace && diff --git a/testing/taskcluster/tasks/builds/b2g_flame_kk_ota_debug.yml b/testing/taskcluster/tasks/builds/b2g_flame_kk_ota_debug.yml index 634725d39434..ed19afcbe5bb 100644 --- a/testing/taskcluster/tasks/builds/b2g_flame_kk_ota_debug.yml +++ b/testing/taskcluster/tasks/builds/b2g_flame_kk_ota_debug.yml @@ -17,4 +17,3 @@ task: env: VARIANT: userdebug B2G_DEBUG: 0 - TOOLTOOL_MANIFEST: 'b2g/config/flame-kk-ota/releng-flame-kk-ota.tt' \ No newline at end of file diff --git a/testing/taskcluster/tasks/builds/b2g_flame_kk_ota_opt.yml b/testing/taskcluster/tasks/builds/b2g_flame_kk_ota_opt.yml index 37fc84205341..0be3a4c569af 100644 --- a/testing/taskcluster/tasks/builds/b2g_flame_kk_ota_opt.yml +++ b/testing/taskcluster/tasks/builds/b2g_flame_kk_ota_opt.yml @@ -16,4 +16,3 @@ task: build-flame-kk-ota-user-objdir-gecko-{{project}}: /home/worker/objdir-gecko env: VARIANT: user - TOOLTOOL_MANIFEST: 'b2g/config/flame-kk-ota/releng-flame-kk-ota.tt' \ No newline at end of file diff --git a/testing/taskcluster/tasks/builds/b2g_flame_kk_spark_eng.yml b/testing/taskcluster/tasks/builds/b2g_flame_kk_spark_eng.yml index 4e2eeb0d878c..87150044afc7 100644 --- a/testing/taskcluster/tasks/builds/b2g_flame_kk_spark_eng.yml +++ b/testing/taskcluster/tasks/builds/b2g_flame_kk_spark_eng.yml @@ -17,7 +17,6 @@ task: env: TARGET: 'flame-kk' MOZHARNESS_CONFIG: b2g/taskcluster-spark.py - TOOLTOOL_MANIFEST: 'b2g/config/flame-kk/releng-flame-kk.tt' extra: treeherderEnv: - staging diff --git a/testing/taskcluster/tasks/builds/b2g_nexus_4_eng.yml b/testing/taskcluster/tasks/builds/b2g_nexus_4_eng.yml index 176a36a64eb2..1f725f1da679 100644 --- a/testing/taskcluster/tasks/builds/b2g_nexus_4_eng.yml +++ b/testing/taskcluster/tasks/builds/b2g_nexus_4_eng.yml @@ -15,7 +15,6 @@ task: env: TARGET: 'nexus-4' DEBUG: 0 - TOOLTOOL_MANIFEST: 'b2g/config/nexus-4/releng-mako.tt' command: - > checkout-gecko workspace && diff --git a/testing/taskcluster/tasks/builds/b2g_nexus_4_kk_eng.yml b/testing/taskcluster/tasks/builds/b2g_nexus_4_kk_eng.yml index 711329410a06..4265ea6ee247 100644 --- a/testing/taskcluster/tasks/builds/b2g_nexus_4_kk_eng.yml +++ b/testing/taskcluster/tasks/builds/b2g_nexus_4_kk_eng.yml @@ -17,7 +17,6 @@ task: env: TARGET: 'nexus-4-kk' DEBUG: 0 - TOOLTOOL_MANIFEST: 'b2g/config/nexus-4-kk/releng-mako.tt' command: - > checkout-gecko workspace && diff --git a/testing/taskcluster/tasks/builds/b2g_nexus_4_kk_user.yml b/testing/taskcluster/tasks/builds/b2g_nexus_4_kk_user.yml index 1e47aaf95f0a..b2dbf01e98dd 100644 --- a/testing/taskcluster/tasks/builds/b2g_nexus_4_kk_user.yml +++ b/testing/taskcluster/tasks/builds/b2g_nexus_4_kk_user.yml @@ -17,7 +17,6 @@ task: env: TARGET: 'nexus-4-kk' DEBUG: 0 - TOOLTOOL_MANIFEST: 'b2g/config/nexus-4-kk/releng-mako.tt' command: - > checkout-gecko workspace && diff --git a/testing/taskcluster/tasks/builds/b2g_nexus_4_user.yml b/testing/taskcluster/tasks/builds/b2g_nexus_4_user.yml index 31248eb6e4d8..e7a8423b7555 100644 --- a/testing/taskcluster/tasks/builds/b2g_nexus_4_user.yml +++ b/testing/taskcluster/tasks/builds/b2g_nexus_4_user.yml @@ -16,7 +16,6 @@ task: env: TARGET: 'nexus-4' DEBUG: 0 - TOOLTOOL_MANIFEST: 'b2g/config/nexus-4/releng-mako.tt' command: - > checkout-gecko workspace && diff --git a/testing/taskcluster/tasks/builds/b2g_nexus_5l_eng.yml b/testing/taskcluster/tasks/builds/b2g_nexus_5l_eng.yml index 6ceb7a036cab..20591c022a3a 100644 --- a/testing/taskcluster/tasks/builds/b2g_nexus_5l_eng.yml +++ b/testing/taskcluster/tasks/builds/b2g_nexus_5l_eng.yml @@ -15,7 +15,6 @@ task: env: TARGET: 'nexus-5-l' DEBUG: 0 - TOOLTOOL_MANIFEST: 'b2g/config/nexus-5-l/releng-nexus5.tt' command: - > checkout-gecko workspace && diff --git a/testing/taskcluster/tasks/builds/b2g_nexus_5l_user.yml b/testing/taskcluster/tasks/builds/b2g_nexus_5l_user.yml index 01eb8832f282..b6321287c4b5 100644 --- a/testing/taskcluster/tasks/builds/b2g_nexus_5l_user.yml +++ b/testing/taskcluster/tasks/builds/b2g_nexus_5l_user.yml @@ -16,7 +16,6 @@ task: env: TARGET: 'nexus-5-l' DEBUG: 0 - TOOLTOOL_MANIFEST: 'b2g/config/nexus-5-l/releng-nexus5.tt' command: - > checkout-gecko workspace && diff --git a/testing/taskcluster/tasks/builds/b2g_phone_base.yml b/testing/taskcluster/tasks/builds/b2g_phone_base.yml index 1e00c07e9aff..1ab2648fe3db 100644 --- a/testing/taskcluster/tasks/builds/b2g_phone_base.yml +++ b/testing/taskcluster/tasks/builds/b2g_phone_base.yml @@ -1,14 +1,10 @@ $inherits: from: 'tasks/phone_build.yml' task: - scopes: - - 'docker-worker:cache:tooltool-cache' metadata: description: | Android phones + b2g environment used in full stack testing. payload: - cache: - tooltool-cache: '/home/worker/tooltool-cache' env: MOZILLA_OFFICIAL: '1' ENABLE_DEFAULT_BOOTANIMATION: 'true' diff --git a/testing/taskcluster/tasks/phone_build.yml b/testing/taskcluster/tasks/phone_build.yml index 08b9f518b7b1..9ef39d34611c 100644 --- a/testing/taskcluster/tasks/phone_build.yml +++ b/testing/taskcluster/tasks/phone_build.yml @@ -54,8 +54,6 @@ task: GECKO_HEAD_REPOSITORY: '{{head_repository}}' GECKO_HEAD_REV: '{{head_rev}}' GECKO_HEAD_REF: '{{head_ref}}' - TOOLTOOL_REPO: 'https://git.mozilla.org/build/tooltool.git' - TOOLTOOL_REV: 'master' extra: build_product: 'b2g' From 81b84d2ae9ffe2443365cccc183b74213f72ba57 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Tue, 6 Oct 2015 17:51:23 -0700 Subject: [PATCH 110/228] Backed out changeset 10aca6716dc3 (bug 1207548) for flame-kk build failures --- testing/taskcluster/tasks/tests/b2g_build_test.yml | 2 +- testing/taskcluster/tasks/tests/b2g_emulator_mochitest.yml | 3 +-- .../taskcluster/tasks/tests/b2g_emulator_mochitest_media.yml | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/testing/taskcluster/tasks/tests/b2g_build_test.yml b/testing/taskcluster/tasks/tests/b2g_build_test.yml index f829daa9c59c..5862175a799c 100644 --- a/testing/taskcluster/tasks/tests/b2g_build_test.yml +++ b/testing/taskcluster/tasks/tests/b2g_build_test.yml @@ -22,7 +22,7 @@ task: --download-symbols ondemand --gaia-repo https://hg.mozilla.org/integration/gaia-central --gaia-dir /home/worker - --xre-url http://people.mozilla.org/~jdai/xulrunner-sdk-40.zip + --xre-url https://queue.taskcluster.net/v1/task/wXAHAaxDQpqxoWF1iljJjg/runs/0/artifacts/public/cache/xulrunner-sdk-40.zip artifacts: 'public/build': type: directory diff --git a/testing/taskcluster/tasks/tests/b2g_emulator_mochitest.yml b/testing/taskcluster/tasks/tests/b2g_emulator_mochitest.yml index b38b4dd77ff7..a5850f56d285 100644 --- a/testing/taskcluster/tasks/tests/b2g_emulator_mochitest.yml +++ b/testing/taskcluster/tasks/tests/b2g_emulator_mochitest.yml @@ -13,7 +13,6 @@ task: - entrypoint - > python ./mozharness/scripts/b2g_emulator_unittest.py - --no-read-buildbot-config --config-file ./mozharness/configs/b2g/emulator_automation_config.py --config-file ./mozharness_configs/gaia_integration_override.py --config-file ./mozharness_configs/emulator_override.py @@ -22,7 +21,7 @@ task: --test-suite mochitest --installer-url {{build_url}} --test-packages-url {{test_packages_url}} - --xre-url http://people.mozilla.org/~jdai/xulrunner-sdk-40.zip + --xre-url https://queue.taskcluster.net/v1/task/wXAHAaxDQpqxoWF1iljJjg/runs/0/artifacts/public/cache/xulrunner-sdk-40.zip --this-chunk {{chunk}} --total-chunk {{total_chunks}} artifacts: diff --git a/testing/taskcluster/tasks/tests/b2g_emulator_mochitest_media.yml b/testing/taskcluster/tasks/tests/b2g_emulator_mochitest_media.yml index 773677b13b8f..50fd012d834f 100644 --- a/testing/taskcluster/tasks/tests/b2g_emulator_mochitest_media.yml +++ b/testing/taskcluster/tasks/tests/b2g_emulator_mochitest_media.yml @@ -12,7 +12,6 @@ task: - entrypoint - > python ./mozharness/scripts/b2g_emulator_unittest.py - --no-read-buildbot-config --config-file ./mozharness/configs/b2g/emulator_automation_config.py --config-file ./mozharness_configs/gaia_integration_override.py --config-file ./mozharness_configs/emulator_override.py @@ -21,7 +20,7 @@ task: --test-suite mochitest --installer-url {{build_url}} --test-packages-url {{test_packages_url}} - --xre-url http://people.mozilla.org/~jdai/xulrunner-sdk-40.zip + --xre-url https://queue.taskcluster.net/v1/task/wXAHAaxDQpqxoWF1iljJjg/runs/0/artifacts/public/cache/xulrunner-sdk-40.zip dom/media/tests artifacts: 'public/build': From d5e52e1fca7d6accef59d1f6bd88f0ccd152e3da Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 6 Oct 2015 16:36:10 +1300 Subject: [PATCH 111/228] Bug 1195152. Pass correct YUV type when converting shared YUV image to RGB. r=nical --HG-- extra : commitid : 6wWAshcHBaB extra : rebase_source : b9099c20a74f3cc569ae5b3bf895ac749cabd9fa --- gfx/layers/YCbCrImageDataSerializer.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gfx/layers/YCbCrImageDataSerializer.cpp b/gfx/layers/YCbCrImageDataSerializer.cpp index 9ef0034e7d5d..29b964a9704b 100644 --- a/gfx/layers/YCbCrImageDataSerializer.cpp +++ b/gfx/layers/YCbCrImageDataSerializer.cpp @@ -292,13 +292,14 @@ YCbCrImageDataDeserializer::ToDataSourceSurface() return nullptr; } + gfx::YUVType type = TypeFromSize(GetYSize().width, GetYSize().height, + GetCbCrSize().width, GetCbCrSize().height); gfx::ConvertYCbCrToRGB32(GetYData(), GetCbData(), GetCrData(), map.mData, 0, 0, //pic x and y GetYSize().width, GetYSize().height, GetYStride(), GetCbCrStride(), - map.mStride, - gfx::YV12); + map.mStride, type); result->Unmap(); return result.forget(); } From c0eb7d9a66498ae2e98019fecfbce05db15e04cd Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Wed, 7 Oct 2015 14:04:32 +1100 Subject: [PATCH 112/228] Bug 1126230 part 1 - Use delegated constructor to simplify constructor of nsFrameConstructorState. r=bz --HG-- extra : source : a6d09835f9c0e76e01e71e46ac978f4e8e16f97f --- layout/base/nsCSSFrameConstructor.cpp | 60 +++++++++------------------ 1 file changed, 19 insertions(+), 41 deletions(-) diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 82777fdbb6e6..8fee21a2bfaf 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -777,11 +777,12 @@ public: // Constructor // Use the passed-in history state. - nsFrameConstructorState(nsIPresShell* aPresShell, - nsContainerFrame* aFixedContainingBlock, - nsContainerFrame* aAbsoluteContainingBlock, - nsContainerFrame* aFloatContainingBlock, - nsILayoutHistoryState* aHistoryState); + nsFrameConstructorState( + nsIPresShell* aPresShell, + nsContainerFrame* aFixedContainingBlock, + nsContainerFrame* aAbsoluteContainingBlock, + nsContainerFrame* aFloatContainingBlock, + already_AddRefed aHistoryState); // Get the history state from the pres context's pres shell. nsFrameConstructorState(nsIPresShell* aPresShell, nsContainerFrame* aFixedContainingBlock, @@ -921,11 +922,12 @@ protected: PendingBinding* mCurrentPendingBindingInsertionPoint; }; -nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShell, - nsContainerFrame* aFixedContainingBlock, - nsContainerFrame* aAbsoluteContainingBlock, - nsContainerFrame* aFloatContainingBlock, - nsILayoutHistoryState* aHistoryState) +nsFrameConstructorState::nsFrameConstructorState( + nsIPresShell* aPresShell, + nsContainerFrame* aFixedContainingBlock, + nsContainerFrame* aAbsoluteContainingBlock, + nsContainerFrame* aFloatContainingBlock, + already_AddRefed aHistoryState) : mPresContext(aPresShell->GetPresContext()), mPresShell(aPresShell), mFrameManager(aPresShell->FrameManager()), @@ -961,35 +963,11 @@ nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShell, nsContainerFrame* aFixedContainingBlock, nsContainerFrame* aAbsoluteContainingBlock, nsContainerFrame* aFloatContainingBlock) - : mPresContext(aPresShell->GetPresContext()), - mPresShell(aPresShell), - mFrameManager(aPresShell->FrameManager()), -#ifdef MOZ_XUL - mPopupItems(nullptr), -#endif - mFixedItems(aFixedContainingBlock), - mAbsoluteItems(aAbsoluteContainingBlock), - mFloatedItems(aFloatContainingBlock), - // See PushAbsoluteContaningBlock below - mAdditionalStateBits(nsFrameState(0)), - // If the fixed-pos containing block is equal to the abs-pos containing - // block, use the abs-pos containing block's abs-pos list for fixed-pos - // frames. - mFixedPosIsAbsPos(aFixedContainingBlock == aAbsoluteContainingBlock), - mHavePendingPopupgroup(false), - mCreatingExtraFrames(false), - mTreeMatchContext(true, nsRuleWalker::eRelevantLinkUnvisited, - aPresShell->GetDocument()), - mCurrentPendingBindingInsertionPoint(nullptr) + : nsFrameConstructorState(aPresShell, aFixedContainingBlock, + aAbsoluteContainingBlock, + aFloatContainingBlock, + aPresShell->GetDocument()->GetLayoutHistoryState()) { -#ifdef MOZ_XUL - nsIRootBox* rootBox = nsIRootBox::GetRootBox(aPresShell); - if (rootBox) { - mPopupItems.containingBlock = rootBox->GetPopupSetFrame(); - } -#endif - MOZ_COUNT_CTOR(nsFrameConstructorState); - mFrameState = aPresShell->GetDocument()->GetLayoutHistoryState(); } nsFrameConstructorState::~nsFrameConstructorState() @@ -2322,7 +2300,7 @@ nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocEle nsFrameConstructorState state(mPresShell, GetAbsoluteContainingBlock(mDocElementContainingBlock, FIXED_POS), nullptr, - nullptr, aFrameState); + nullptr, do_AddRef(Move(aFrameState))); // Initialize the ancestor filter with null for now; we'll push // aDocElement once we finish resolving style for it. state.mTreeMatchContext.InitAncestors(nullptr); @@ -7548,7 +7526,7 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer, GetAbsoluteContainingBlock(insertion.mParentFrame, FIXED_POS), GetAbsoluteContainingBlock(insertion.mParentFrame, ABS_POS), GetFloatContainingBlock(insertion.mParentFrame), - aFrameState); + do_AddRef(Move(aFrameState))); state.mTreeMatchContext.InitAncestors(aContainer ? aContainer->AsElement() : nullptr); @@ -11264,7 +11242,7 @@ nsCSSFrameConstructor::CreateListBoxContent(nsPresContext* aPresContext, nsFrameConstructorState state(mPresShell, GetAbsoluteContainingBlock(aParentFrame, FIXED_POS), GetAbsoluteContainingBlock(aParentFrame, ABS_POS), GetFloatContainingBlock(aParentFrame), - mTempFrameTreeState); + do_AddRef(mTempFrameTreeState.get())); // If we ever initialize the ancestor filter on |state|, make sure // to push the right parent! From 761df5aae4db50d2dc7a249cd0ade8b41a03c2f1 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Wed, 7 Oct 2015 14:04:32 +1100 Subject: [PATCH 113/228] Bug 1126230 part 2 - Refactor part of nsFrameConstructorState::AddChild. r=bz --HG-- extra : source : 1ac324a35bd2ecea3a0c4616b9c4c28fc5146fc7 --- layout/base/nsCSSFrameConstructor.cpp | 105 +++++++++++++++----------- 1 file changed, 62 insertions(+), 43 deletions(-) diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 8fee21a2bfaf..7fbb742bd9a4 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -915,6 +915,20 @@ protected: void ProcessFrameInsertions(nsAbsoluteItems& aFrameItems, ChildListID aChildListID); + /** + * GetOutOfFlowFrameItems selects the out-of-flow frame list the new + * frame should be added to. If the frame shouldn't be added to any + * out-of-flow list, it returns nullptr. The corresponding type of + * placeholder is also returned via the aPlaceholderType parameter + * if this method doesn't return nullptr. The caller should check + * whether the returned list really has a containing block. + */ + nsAbsoluteItems* GetOutOfFlowFrameItems(nsIFrame* aNewFrame, + bool aCanBePositioned, + bool aCanBeFloated, + bool aIsOutOfFlowPopup, + nsFrameState* aPlaceholderType); + // Our list of all pending bindings. When we're done, we need to call // AddToAttachedQueue on all of them, in order. LinkedList mPendingBindings; @@ -1101,6 +1115,39 @@ nsFrameConstructorState::GetGeometricParent(const nsStyleDisplay* aStyleDisplay, return aContentParentFrame; } +nsAbsoluteItems* +nsFrameConstructorState::GetOutOfFlowFrameItems(nsIFrame* aNewFrame, + bool aCanBePositioned, + bool aCanBeFloated, + bool aIsOutOfFlowPopup, + nsFrameState* aPlaceholderType) +{ +#ifdef MOZ_XUL + if (MOZ_UNLIKELY(aIsOutOfFlowPopup)) { + MOZ_ASSERT(mPopupItems.containingBlock, "Must have a popup set frame!"); + *aPlaceholderType = PLACEHOLDER_FOR_POPUP; + return &mPopupItems; + } +#endif // MOZ_XUL + if (aCanBeFloated && aNewFrame->IsFloating()) { + *aPlaceholderType = PLACEHOLDER_FOR_FLOAT; + return &mFloatedItems; + } + + if (aCanBePositioned) { + const nsStyleDisplay* disp = aNewFrame->StyleDisplay(); + if (disp->mPosition == NS_STYLE_POSITION_ABSOLUTE) { + *aPlaceholderType = PLACEHOLDER_FOR_ABSPOS; + return &mAbsoluteItems; + } + if (disp->mPosition == NS_STYLE_POSITION_FIXED) { + *aPlaceholderType = PLACEHOLDER_FOR_FIXEDPOS; + return &GetFixedItems(); + } + } + return nullptr; +} + void nsFrameConstructorState::AddChild(nsIFrame* aNewFrame, nsFrameItems& aFrameItems, @@ -1115,53 +1162,25 @@ nsFrameConstructorState::AddChild(nsIFrame* aNewFrame, { NS_PRECONDITION(!aNewFrame->GetNextSibling(), "Shouldn't happen"); - const nsStyleDisplay* disp = aNewFrame->StyleDisplay(); + nsFrameState placeholderType; + nsAbsoluteItems* outOfFlowFrameItems = + GetOutOfFlowFrameItems(aNewFrame, aCanBePositioned, aCanBeFloated, + aIsOutOfFlowPopup, &placeholderType); // The comments in GetGeometricParent regarding root table frames - // all apply here, unfortunately. - - bool needPlaceholder = false; - nsFrameState placeholderType; - nsFrameItems* frameItems = &aFrameItems; -#ifdef MOZ_XUL - if (MOZ_UNLIKELY(aIsOutOfFlowPopup)) { - NS_ASSERTION(aNewFrame->GetParent() == mPopupItems.containingBlock, - "Popup whose parent is not the popup containing block?"); - NS_ASSERTION(mPopupItems.containingBlock, "Must have a popup set frame!"); - needPlaceholder = true; - frameItems = &mPopupItems; - placeholderType = PLACEHOLDER_FOR_POPUP; - } - else -#endif // MOZ_XUL - if (aCanBeFloated && aNewFrame->IsFloating() && - mFloatedItems.containingBlock) { - NS_ASSERTION(aNewFrame->GetParent() == mFloatedItems.containingBlock, - "Float whose parent is not the float containing block?"); - needPlaceholder = true; - frameItems = &mFloatedItems; - placeholderType = PLACEHOLDER_FOR_FLOAT; - } - else if (aCanBePositioned) { - if (disp->mPosition == NS_STYLE_POSITION_ABSOLUTE && - mAbsoluteItems.containingBlock) { - NS_ASSERTION(aNewFrame->GetParent() == mAbsoluteItems.containingBlock, - "Abs pos whose parent is not the abs pos containing block?"); - needPlaceholder = true; - frameItems = &mAbsoluteItems; - placeholderType = PLACEHOLDER_FOR_ABSPOS; - } - if (disp->mPosition == NS_STYLE_POSITION_FIXED && - GetFixedItems().containingBlock) { - NS_ASSERTION(aNewFrame->GetParent() == GetFixedItems().containingBlock, - "Fixed pos whose parent is not the fixed pos containing block?"); - needPlaceholder = true; - frameItems = &GetFixedItems(); - placeholderType = PLACEHOLDER_FOR_FIXEDPOS; - } + // all apply here, unfortunately. Thus, we need to check whether + // the returned frame items really has containing block. + nsFrameItems* frameItems; + if (outOfFlowFrameItems && outOfFlowFrameItems->containingBlock) { + MOZ_ASSERT(aNewFrame->GetParent() == outOfFlowFrameItems->containingBlock, + "Parent of the frame is not the containing block?"); + frameItems = outOfFlowFrameItems; + } else { + frameItems = &aFrameItems; + placeholderType = nsFrameState(0); } - if (needPlaceholder) { + if (placeholderType) { NS_ASSERTION(frameItems != &aFrameItems, "Putting frame in-flow _and_ want a placeholder?"); nsIFrame* placeholderFrame = From da7b2245c771d733dc07b11ef41bd0f674690c80 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Wed, 7 Oct 2015 14:04:32 +1100 Subject: [PATCH 114/228] Bug 1126230 part 3 - Add :-moz-browser-frame pseudo class for HTML browser frame elements. r=dbaron --HG-- extra : source : 748700369c0626e36b6585c11398e5f8fc0fc44f --- layout/style/nsCSSPseudoClassList.h | 3 +++ layout/style/nsCSSRuleProcessor.cpp | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/layout/style/nsCSSPseudoClassList.h b/layout/style/nsCSSPseudoClassList.h index 45947cd63356..bca620b5c59a 100644 --- a/layout/style/nsCSSPseudoClassList.h +++ b/layout/style/nsCSSPseudoClassList.h @@ -122,6 +122,9 @@ CSS_PSEUDO_CLASS(mozWindowInactive, ":-moz-window-inactive", 0, "") // according to HTML integer attribute parsing rules. CSS_PSEUDO_CLASS(mozTableBorderNonzero, ":-moz-table-border-nonzero", 0, "") +// Matches HTML frame/iframe elements which are mozbrowser. +CSS_PSEUDO_CLASS(mozBrowserFrame, ":-moz-browser-frame", 0, "") + // Matches whatever the contextual reference elements are for the // matching operation. CSS_PSEUDO_CLASS(scope, ":scope", 0, "layout.css.scope-pseudo.enabled") diff --git a/layout/style/nsCSSRuleProcessor.cpp b/layout/style/nsCSSRuleProcessor.cpp index bda7db3f698e..e65dde741eb7 100644 --- a/layout/style/nsCSSRuleProcessor.cpp +++ b/layout/style/nsCSSRuleProcessor.cpp @@ -56,6 +56,7 @@ #include "mozilla/TypedEnumBits.h" #include "RuleProcessorCache.h" #include "nsIDOMMutationEvent.h" +#include "nsIMozBrowserFrame.h" using namespace mozilla; using namespace mozilla::dom; @@ -2156,6 +2157,17 @@ static bool SelectorMatches(Element* aElement, } break; + case nsCSSPseudoClasses::ePseudoClass_mozBrowserFrame: + { + nsCOMPtr + browserFrame = do_QueryInterface(aElement); + if (!browserFrame || + !browserFrame->GetReallyIsBrowserOrApp()) { + return false; + } + } + break; + case nsCSSPseudoClasses::ePseudoClass_dir: { if (aDependence) { From e9db99c05b4e10f23588c4a1b0ffdd88a7a4853a Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Wed, 7 Oct 2015 14:04:32 +1100 Subject: [PATCH 115/228] Bug 1126230 part 4 - Add -moz-top-layer internal CSS property and set it for fullscreen elements. r=dbaron --HG-- extra : source : 66def85f28a64f87a9bf072754a3146aacb59714 --- layout/style/nsCSSPropList.h | 16 +++++++++++++++- layout/style/nsCSSProps.cpp | 6 ++++++ layout/style/nsCSSProps.h | 1 + layout/style/nsRuleNode.cpp | 17 +++++++++++++++++ layout/style/nsStyleConsts.h | 4 ++++ layout/style/nsStyleStruct.cpp | 3 +++ layout/style/nsStyleStruct.h | 1 + layout/style/test/ListCSSProperties.cpp | 1 + layout/style/ua.css | 6 +++++- 9 files changed, 53 insertions(+), 2 deletions(-) diff --git a/layout/style/nsCSSPropList.h b/layout/style/nsCSSPropList.h index 3a6e13944cac..5cdb632bdb93 100644 --- a/layout/style/nsCSSPropList.h +++ b/layout/style/nsCSSPropList.h @@ -3414,7 +3414,21 @@ CSS_PROP_POSITION( nullptr, offsetof(nsStylePosition, mOffset), eStyleAnimType_Sides_Top) - CSS_PROP_DISPLAY( +#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL +CSS_PROP_DISPLAY( + -moz-top-layer, + _moz_top_layer, + CSS_PROP_DOMPROP_PREFIXED(TopLayer), + CSS_PROPERTY_INTERNAL | + CSS_PROPERTY_PARSE_VALUE | + CSS_PROPERTY_ENABLED_IN_UA_SHEETS, + "", + VARIANT_HK, + kTopLayerKTable, + CSS_PROP_NO_OFFSET, + eStyleAnimType_None) +#endif // CSS_PROP_LIST_EXCLUDE_INTERNAL +CSS_PROP_DISPLAY( touch-action, touch_action, TouchAction, diff --git a/layout/style/nsCSSProps.cpp b/layout/style/nsCSSProps.cpp index 1b420e9292c2..05319f470721 100644 --- a/layout/style/nsCSSProps.cpp +++ b/layout/style/nsCSSProps.cpp @@ -1834,6 +1834,12 @@ const KTableValue nsCSSProps::kTouchActionKTable[] = { eCSSKeyword_UNKNOWN, -1 }; +const KTableValue nsCSSProps::kTopLayerKTable[] = { + eCSSKeyword_none, NS_STYLE_TOP_LAYER_NONE, + eCSSKeyword_top, NS_STYLE_TOP_LAYER_TOP, + eCSSKeyword_UNKNOWN, -1 +}; + const KTableValue nsCSSProps::kTransformBoxKTable[] = { eCSSKeyword_border_box, NS_STYLE_TRANSFORM_BOX_BORDER_BOX, eCSSKeyword_fill_box, NS_STYLE_TRANSFORM_BOX_FILL_BOX, diff --git a/layout/style/nsCSSProps.h b/layout/style/nsCSSProps.h index 33ddafa36720..2fcd5dacc359 100644 --- a/layout/style/nsCSSProps.h +++ b/layout/style/nsCSSProps.h @@ -750,6 +750,7 @@ public: static const KTableValue kTextOverflowKTable[]; static const KTableValue kTextTransformKTable[]; static const KTableValue kTouchActionKTable[]; + static const KTableValue kTopLayerKTable[]; static const KTableValue kTransformBoxKTable[]; static const KTableValue kTransitionTimingFunctionKTable[]; static const KTableValue kUnicodeBidiKTable[]; diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp index 51a0fa4522dc..cfa88c3cfdc2 100644 --- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -5446,6 +5446,13 @@ nsRuleNode::ComputeDisplayData(void* aStartStruct, parentDisplay->mIsolation, NS_STYLE_ISOLATION_AUTO, 0, 0, 0, 0); + // -moz-top-layer: enum, inherit, initial + SetDiscrete(*aRuleData->ValueForTopLayer(), display->mTopLayer, + conditions, + SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL, + parentDisplay->mTopLayer, NS_STYLE_TOP_LAYER_NONE, + 0, 0, 0, 0); + // Backup original display value for calculation of a hypothetical // box (CSS2 10.6.4/10.6.5), in addition to getting our style data right later. // See nsHTMLReflowState::CalculateHypotheticalBox @@ -5485,6 +5492,16 @@ nsRuleNode::ComputeDisplayData(void* aStartStruct, SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL, parentDisplay->mPosition, NS_STYLE_POSITION_STATIC, 0, 0, 0, 0); + // If an element is put in the top layer, while it is not absolutely + // positioned, the position value should be computed to 'absolute' per + // the Fullscreen API spec. + if (display->mTopLayer != NS_STYLE_TOP_LAYER_NONE && + !display->IsAbsolutelyPositionedStyle()) { + display->mPosition = NS_STYLE_POSITION_ABSOLUTE; + // We cannot cache this struct because otherwise it may be used as + // an aStartStruct for some other elements. + conditions.SetUncacheable(); + } // clear: enum, inherit, initial SetDiscrete(*aRuleData->ValueForClear(), display->mBreakType, conditions, diff --git a/layout/style/nsStyleConsts.h b/layout/style/nsStyleConsts.h index 14941b65aa37..483ac07d7681 100644 --- a/layout/style/nsStyleConsts.h +++ b/layout/style/nsStyleConsts.h @@ -816,6 +816,10 @@ static inline mozilla::css::Side operator++(mozilla::css::Side& side, int) { #define NS_STYLE_TOUCH_ACTION_PAN_Y (1 << 3) #define NS_STYLE_TOUCH_ACTION_MANIPULATION (1 << 4) +// See nsStyleDisplay +#define NS_STYLE_TOP_LAYER_NONE 0 // not in the top layer +#define NS_STYLE_TOP_LAYER_TOP 1 // in the top layer + // See nsStyleDisplay #define NS_STYLE_TRANSFORM_BOX_BORDER_BOX 0 #define NS_STYLE_TRANSFORM_BOX_FILL_BOX 1 diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index df4b4e607433..26f68bd83ebb 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -2629,6 +2629,7 @@ nsStyleDisplay::nsStyleDisplay() mMixBlendMode = NS_STYLE_BLEND_NORMAL; mIsolation = NS_STYLE_ISOLATION_AUTO; mTouchAction = NS_STYLE_TOUCH_ACTION_AUTO; + mTopLayer = NS_STYLE_TOP_LAYER_NONE; mScrollBehavior = NS_STYLE_SCROLL_BEHAVIOR_AUTO; mScrollSnapTypeX = NS_STYLE_SCROLL_SNAP_TYPE_NONE; mScrollSnapTypeY = NS_STYLE_SCROLL_SNAP_TYPE_NONE; @@ -2683,6 +2684,7 @@ nsStyleDisplay::nsStyleDisplay(const nsStyleDisplay& aSource) , mOrient(aSource.mOrient) , mMixBlendMode(aSource.mMixBlendMode) , mIsolation(aSource.mIsolation) + , mTopLayer(aSource.mTopLayer) , mWillChangeBitField(aSource.mWillChangeBitField) , mWillChange(aSource.mWillChange) , mTouchAction(aSource.mTouchAction) @@ -2740,6 +2742,7 @@ nsChangeHint nsStyleDisplay::CalcDifference(const nsStyleDisplay& aOther) const || mScrollSnapPointsX != aOther.mScrollSnapPointsX || mScrollSnapPointsY != aOther.mScrollSnapPointsY || mScrollSnapDestination != aOther.mScrollSnapDestination + || mTopLayer != aOther.mTopLayer || mResize != aOther.mResize) NS_UpdateHint(hint, nsChangeHint_ReconstructFrame); diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index ee3893052620..c3db787aeb7f 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -2166,6 +2166,7 @@ struct nsStyleDisplay { uint8_t mOrient; // [reset] see nsStyleConsts.h uint8_t mMixBlendMode; // [reset] see nsStyleConsts.h uint8_t mIsolation; // [reset] see nsStyleConsts.h + uint8_t mTopLayer; // [reset] see nsStyleConsts.h uint8_t mWillChangeBitField; // [reset] see nsStyleConsts.h. Stores a // bitfield representation of the properties // that are frequently queried. This should diff --git a/layout/style/test/ListCSSProperties.cpp b/layout/style/test/ListCSSProperties.cpp index dcc892d26f5b..4615f105dfa3 100644 --- a/layout/style/test/ListCSSProperties.cpp +++ b/layout/style/test/ListCSSProperties.cpp @@ -112,6 +112,7 @@ const char *gInaccessibleProperties[] = { "-moz-script-min-size", "-moz-math-variant", "-moz-math-display", // parsed by UA sheets only + "-moz-top-layer", // parsed by UA sheets only "-moz-window-dragging", // chrome-only internal properties "-moz-window-shadow" // chrome-only internal properties }; diff --git a/layout/style/ua.css b/layout/style/ua.css index 859dc38022f0..0d1643b8d967 100644 --- a/layout/style/ua.css +++ b/layout/style/ua.css @@ -262,7 +262,7 @@ } -*|*:not(:root):-moz-full-screen { +*|*:-moz-full-screen:not(:root) { position: fixed !important; top: 0 !important; left: 0 !important; @@ -280,6 +280,10 @@ box-sizing: border-box !important; } +*|*:-moz-full-screen:not(:root):not(:-moz-browser-frame) { + -moz-top-layer: top !important; +} + /* XML parse error reporting */ parsererror|parsererror { From 3a11a2f307af01d13a341b48b3df46898bb93e17 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Wed, 7 Oct 2015 14:04:32 +1100 Subject: [PATCH 116/228] Bug 1126230 part 5 - Give proper geometric parent for top layer frames. r=bz,dbaron --HG-- extra : source : ad496022ecf04e001fcbedb70ef057a8c068ccb7 --- layout/base/nsCSSFrameConstructor.cpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 7fbb742bd9a4..1dbc161bf593 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -744,6 +744,11 @@ public: nsAbsoluteItems mFixedItems; nsAbsoluteItems mAbsoluteItems; nsAbsoluteItems mFloatedItems; + // Items in the top layer are always fixed positioned children of the + // viewport frame. It differs from mFixedItems that the items here + // should not be caught by any other fixed-pos containing block like + // frames with transform or filter. + nsAbsoluteItems mTopLayerItems; nsCOMPtr mFrameState; // These bits will be added to the state bits of any frame we construct @@ -951,6 +956,7 @@ nsFrameConstructorState::nsFrameConstructorState( mFixedItems(aFixedContainingBlock), mAbsoluteItems(aAbsoluteContainingBlock), mFloatedItems(aFloatContainingBlock), + mTopLayerItems(do_QueryFrame(mFrameManager->GetRootFrame())), // See PushAbsoluteContaningBlock below mFrameState(aHistoryState), mAdditionalStateBits(nsFrameState(0)), @@ -987,6 +993,8 @@ nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShell, nsFrameConstructorState::~nsFrameConstructorState() { MOZ_COUNT_DTOR(nsFrameConstructorState); + // Items in the top layer are fixed positioned children of the viewport frame. + ProcessFrameInsertions(mTopLayerItems, nsIFrame::kFixedList); ProcessFrameInsertions(mFloatedItems, nsIFrame::kFloatList); ProcessFrameInsertions(mAbsoluteItems, nsIFrame::kAbsoluteList); ProcessFrameInsertions(mFixedItems, nsIFrame::kFixedList); @@ -1102,6 +1110,15 @@ nsFrameConstructorState::GetGeometricParent(const nsStyleDisplay* aStyleDisplay, return mFloatedItems.containingBlock; } + if (aStyleDisplay->mTopLayer != NS_STYLE_TOP_LAYER_NONE) { + MOZ_ASSERT(aStyleDisplay->mTopLayer == NS_STYLE_TOP_LAYER_TOP, + "-moz-top-layer should be either none or top"); + MOZ_ASSERT(mTopLayerItems.containingBlock, "No root frame?"); + MOZ_ASSERT(aStyleDisplay->IsAbsolutelyPositionedStyle(), + "Top layer items should always be absolutely positioned"); + return mTopLayerItems.containingBlock; + } + if (aStyleDisplay->mPosition == NS_STYLE_POSITION_ABSOLUTE && mAbsoluteItems.containingBlock) { return mAbsoluteItems.containingBlock; @@ -1136,6 +1153,10 @@ nsFrameConstructorState::GetOutOfFlowFrameItems(nsIFrame* aNewFrame, if (aCanBePositioned) { const nsStyleDisplay* disp = aNewFrame->StyleDisplay(); + if (disp->mTopLayer != NS_STYLE_TOP_LAYER_NONE) { + *aPlaceholderType = PLACEHOLDER_FOR_FIXEDPOS; + return &mTopLayerItems; + } if (disp->mPosition == NS_STYLE_POSITION_ABSOLUTE) { *aPlaceholderType = PLACEHOLDER_FOR_ABSPOS; return &mAbsoluteItems; @@ -1218,7 +1239,8 @@ nsFrameConstructorState::ProcessFrameInsertions(nsAbsoluteItems& aFrameItems, aChildListID == nsIFrame::kFloatList) || \ (&aFrameItems == &mAbsoluteItems && \ aChildListID == nsIFrame::kAbsoluteList) || \ - (&aFrameItems == &mFixedItems && \ + ((&aFrameItems == &mFixedItems || \ + &aFrameItems == &mTopLayerItems) && \ aChildListID == nsIFrame::kFixedList) #ifdef MOZ_XUL NS_PRECONDITION(NS_NONXUL_LIST_TEST || From a030778467dbc2282e469d380700f0a2afcf4858 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Wed, 7 Oct 2015 14:04:32 +1100 Subject: [PATCH 117/228] Bug 1126230 part 6 - Add nsIDocument::GetFullscreenStack() method. r=smaug --HG-- extra : source : fd0e6295736145ff6189b04d1ebc1948c3b5a3c3 --- dom/base/nsDocument.cpp | 13 +++++++++++++ dom/base/nsDocument.h | 1 + dom/base/nsIDocument.h | 9 +++++++-- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 785b72dc2a88..d48eb3894d04 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -11441,6 +11441,19 @@ nsDocument::FullScreenStackTop() return element; } +/* virtual */ nsTArray +nsDocument::GetFullscreenStack() const +{ + nsTArray elements; + for (const nsWeakPtr& ptr : mFullScreenStack) { + if (nsCOMPtr elem = do_QueryReferent(ptr)) { + MOZ_ASSERT(elem->State().HasState(NS_EVENT_STATE_FULL_SCREEN)); + elements.AppendElement(elem); + } + } + return elements; +} + // Returns true if aDoc is in the focused tab in the active window. static bool IsInActiveTab(nsIDocument* aDoc) diff --git a/dom/base/nsDocument.h b/dom/base/nsDocument.h index 5606647ce365..b1afd3575f3c 100644 --- a/dom/base/nsDocument.h +++ b/dom/base/nsDocument.h @@ -1207,6 +1207,7 @@ public: virtual Element* FindImageMap(const nsAString& aNormalizedMapName) override; virtual Element* GetFullScreenElement() override; + virtual nsTArray GetFullscreenStack() const override; virtual void AsyncRequestFullScreen( mozilla::UniquePtr&& aRequest) override; virtual void RestorePreviousFullScreenState() override; diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h index 9076c09f4d5e..532a2fc47ff6 100644 --- a/dom/base/nsIDocument.h +++ b/dom/base/nsIDocument.h @@ -155,8 +155,8 @@ typedef CallbackObjectHolder NodeFilterHolder; } // namespace mozilla #define NS_IDOCUMENT_IID \ -{ 0x72391609, 0x673d, 0x4bec, \ - { 0xbd, 0x75, 0x64, 0xbf, 0x1f, 0x6a, 0x6b, 0x5e } } +{ 0x5f51e18c, 0x9e0e, 0x4dc0, \ + { 0x9f, 0x08, 0x7a, 0x32, 0x65, 0x52, 0xea, 0x11 } } // Enum for requesting a particular type of document when creating a doc enum DocumentFlavor { @@ -1094,6 +1094,11 @@ public: */ virtual Element* GetFullScreenElement() = 0; + /** + * Returns all elements in the fullscreen stack in the insertion order. + */ + virtual nsTArray GetFullscreenStack() const = 0; + /** * Asynchronously requests that the document make aElement the fullscreen * element, and move into fullscreen mode. The current fullscreen element From c2d718f5cbb0ca1fb5d53ae0d2c9f16d7e6742ef Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Wed, 7 Oct 2015 14:04:32 +1100 Subject: [PATCH 118/228] Bug 1126230 part 7 - Add static method nsDisplayListBuilder::GetOutOfFlowData(). r=roc --HG-- extra : source : 995811d926293af0bddc1f4738c524b2e9745566 --- layout/base/nsDisplayList.h | 7 +++++++ layout/generic/nsFrame.cpp | 3 +-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index b1b9d8c81d63..898e4e35d8c1 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -864,6 +864,13 @@ public: NS_DECLARE_FRAME_PROPERTY(OutOfFlowDisplayDataProperty, DeleteValue) + + static OutOfFlowDisplayData* GetOutOfFlowData(nsIFrame* aFrame) + { + return static_cast( + aFrame->Properties().Get(OutOfFlowDisplayDataProperty())); + } + NS_DECLARE_FRAME_PROPERTY(Preserve3DDirtyRectProperty, DeleteValue) nsPresContext* CurrentPresContext() { diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 613e3deaf45b..d966157be917 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -2333,8 +2333,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder, // Recheck NS_FRAME_TOO_DEEP_IN_FRAME_TREE if (child->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE) return; - savedOutOfFlowData = static_cast - (child->Properties().Get(nsDisplayListBuilder::OutOfFlowDisplayDataProperty())); + savedOutOfFlowData = nsDisplayListBuilder::GetOutOfFlowData(child); if (savedOutOfFlowData) { dirty = savedOutOfFlowData->mDirtyRect; } else { From 7773a3e41c624fe74045b117da43f84b5742ca12 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Wed, 7 Oct 2015 14:04:32 +1100 Subject: [PATCH 119/228] Bug 1126230 part 8 - Implement painting part for the top layer. r=roc --HG-- extra : source : 4a61841b92db5baf999a9aee02a9aba4799e3d1b --- layout/generic/nsFrame.cpp | 16 +++++- layout/generic/nsViewportFrame.cpp | 90 +++++++++++++++++++++++++++--- layout/generic/nsViewportFrame.h | 3 + layout/style/ua.css | 2 + 4 files changed, 102 insertions(+), 9 deletions(-) diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index d966157be917..8ee469281657 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -2314,9 +2314,12 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder, // dirty rect in child-relative coordinates nsRect dirty = aDirtyRect - child->GetOffsetTo(this); + const nsStyleDisplay* disp; nsIAtom* childType = child->GetType(); nsDisplayListBuilder::OutOfFlowDisplayData* savedOutOfFlowData = nullptr; - if (childType == nsGkAtoms::placeholderFrame) { + if (childType != nsGkAtoms::placeholderFrame) { + disp = child->StyleDisplay(); + } else { nsPlaceholderFrame* placeholder = static_cast(child); child = placeholder->GetOutOfFlowFrame(); NS_ASSERTION(child, "No out of flow frame?"); @@ -2326,6 +2329,16 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder, if (!child || nsLayoutUtils::IsPopup(child) || (child->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT)) return; + MOZ_ASSERT(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW); + disp = child->StyleDisplay(); + // If the out-of-flow frame is in the top layer, the viewport frame + // will paint it. Skip it here. Note that, only out-of-flow frames + // with this property should be skipped, because non-HTML elements + // may stop their children from being out-of-flow. Those frames + // should still be handled in the normal in-flow path. + if (disp->mTopLayer != NS_STYLE_TOP_LAYER_NONE) { + return; + } // Make sure that any attempt to use childType below is disappointed. We // could call GetType again but since we don't currently need it, let's // avoid the virtual call. @@ -2403,7 +2416,6 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder, // Child is composited if it's transformed, partially transparent, or has // SVG effects or a blend mode.. - const nsStyleDisplay* disp = child->StyleDisplay(); const nsStylePosition* pos = child->StylePosition(); bool isVisuallyAtomic = child->HasOpacity() || child->IsTransformed() diff --git a/layout/generic/nsViewportFrame.cpp b/layout/generic/nsViewportFrame.cpp index a0e73a2f4cca..e51066c04386 100644 --- a/layout/generic/nsViewportFrame.cpp +++ b/layout/generic/nsViewportFrame.cpp @@ -14,6 +14,7 @@ #include "nsSubDocumentFrame.h" #include "nsAbsoluteContainingBlock.h" #include "GeckoProfiler.h" +#include "nsIMozBrowserFrame.h" using namespace mozilla; @@ -51,14 +52,89 @@ ViewportFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, PROFILER_LABEL("ViewportFrame", "BuildDisplayList", js::ProfileEntry::Category::GRAPHICS); - nsIFrame* kid = mFrames.FirstChild(); - if (!kid) - return; + if (nsIFrame* kid = mFrames.FirstChild()) { + // make the kid's BorderBackground our own. This ensures that the canvas + // frame's background becomes our own background and therefore appears + // below negative z-index elements. + BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists); + } - // make the kid's BorderBackground our own. This ensures that the canvas - // frame's background becomes our own background and therefore appears - // below negative z-index elements. - BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists); + nsDisplayList topLayerList; + BuildDisplayListForTopLayer(aBuilder, &topLayerList); + if (!topLayerList.IsEmpty()) { + // Wrap the whole top layer in a single item with maximum z-index, + // and append it at the very end, so that it stays at the topmost. + nsDisplayWrapList* wrapList = + new (aBuilder) nsDisplayWrapList(aBuilder, this, &topLayerList); + wrapList->SetOverrideZIndex( + std::numeric_limitsZIndex())>::max()); + aLists.PositionedDescendants()->AppendNewToTop(wrapList); + } +} + +#ifdef DEBUG +/** + * Returns whether we are going to put an element in the top layer for + * fullscreen. This function should matches the CSS rule in ua.css. + */ +static bool +ShouldInTopLayerForFullscreen(Element* aElement) +{ + if (!aElement->GetParent()) { + return false; + } + nsCOMPtr browserFrame = do_QueryInterface(aElement); + if (browserFrame && browserFrame->GetReallyIsBrowserOrApp()) { + return false; + } + return true; +} +#endif // DEBUG + +void +ViewportFrame::BuildDisplayListForTopLayer(nsDisplayListBuilder* aBuilder, + nsDisplayList* aList) +{ + nsIDocument* doc = PresContext()->Document(); + nsTArray fullscreenStack = doc->GetFullscreenStack(); + for (Element* elem : fullscreenStack) { + if (nsIFrame* frame = elem->GetPrimaryFrame()) { + // There are two cases where an element in fullscreen is not in + // the top layer: + // 1. When building display list for purpose other than painting, + // it is possible that there is inconsistency between the style + // info and the content tree. + // 2. This is an element which we are not going to put in the top + // layer for fullscreen. See ShouldInTopLayerForFullscreen(). + // In both cases, we want to skip the frame here and paint it in + // the normal path. + if (frame->StyleDisplay()->mTopLayer == NS_STYLE_TOP_LAYER_NONE) { + MOZ_ASSERT(!aBuilder->IsForPainting() || + !ShouldInTopLayerForFullscreen(elem)); + continue; + } + MOZ_ASSERT(ShouldInTopLayerForFullscreen(elem)); + // Inner SVG, MathML elements, as well as children of some XUL + // elements are not allowed to be out-of-flow. They should not + // be handled as top layer element here. + if (!(frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) { + MOZ_ASSERT(!elem->GetParent()->IsHTMLElement(), "HTML element " + "should always be out-of-flow if in the top layer"); + continue; + } + MOZ_ASSERT(frame->GetParent() == this); + + nsRect dirty; + nsDisplayListBuilder::OutOfFlowDisplayData* + savedOutOfFlowData = nsDisplayListBuilder::GetOutOfFlowData(frame); + if (savedOutOfFlowData) { + dirty = savedOutOfFlowData->mDirtyRect; + } + nsDisplayList list; + frame->BuildDisplayListForStackingContext(aBuilder, dirty, &list); + aList->AppendToTop(&list); + } + } } #ifdef DEBUG diff --git a/layout/generic/nsViewportFrame.h b/layout/generic/nsViewportFrame.h index ad7739363b3c..13b5950454d9 100644 --- a/layout/generic/nsViewportFrame.h +++ b/layout/generic/nsViewportFrame.h @@ -63,6 +63,9 @@ public: const nsRect& aDirtyRect, const nsDisplayListSet& aLists) override; + void BuildDisplayListForTopLayer(nsDisplayListBuilder* aBuilder, + nsDisplayList* aList); + virtual nscoord GetMinISize(nsRenderingContext *aRenderingContext) override; virtual nscoord GetPrefISize(nsRenderingContext *aRenderingContext) override; virtual void Reflow(nsPresContext* aPresContext, diff --git a/layout/style/ua.css b/layout/style/ua.css index 0d1643b8d967..6af848e72725 100644 --- a/layout/style/ua.css +++ b/layout/style/ua.css @@ -280,6 +280,8 @@ box-sizing: border-box !important; } +/* Selectors here should match the check in + * nsViewportFrame.cpp:ShouldInTopLayerForFullscreen() */ *|*:-moz-full-screen:not(:root):not(:-moz-browser-frame) { -moz-top-layer: top !important; } From a52fd07abd96210b5bdf98a3d98c5d7c1034de85 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Wed, 7 Oct 2015 14:04:32 +1100 Subject: [PATCH 120/228] Bug 1126230 part 9 - Remove fullscreen override and related test. r=dbaron --HG-- extra : source : 3abf655d87187abc2d3dcd100a267410c42abbb0 --- ..._fullscreen-ancestor-stacking-context.html | 134 ------------------ dom/html/test/mochitest.ini | 1 - dom/html/test/test_fullscreen-api.html | 1 - layout/base/nsDocumentViewer.cpp | 5 - layout/style/full-screen-override.css | 26 ---- layout/style/jar.mn | 1 - layout/style/nsLayoutStylesheetCache.cpp | 10 -- layout/style/nsLayoutStylesheetCache.h | 2 - 8 files changed, 180 deletions(-) delete mode 100644 dom/html/test/file_fullscreen-ancestor-stacking-context.html delete mode 100644 layout/style/full-screen-override.css diff --git a/dom/html/test/file_fullscreen-ancestor-stacking-context.html b/dom/html/test/file_fullscreen-ancestor-stacking-context.html deleted file mode 100644 index d0b7658c4ec7..000000000000 --- a/dom/html/test/file_fullscreen-ancestor-stacking-context.html +++ /dev/null @@ -1,134 +0,0 @@ - - - - - Test for Bug 1056203 - - - -Mozilla Bug 1056203 -

-

-
-
-
-
-
-
-

-
-
-
- - - diff --git a/dom/html/test/mochitest.ini b/dom/html/test/mochitest.ini index 631867ad48ed..48a74440e52c 100644 --- a/dom/html/test/mochitest.ini +++ b/dom/html/test/mochitest.ini @@ -46,7 +46,6 @@ support-files = file_bug893537.html file_formSubmission_img.jpg file_formSubmission_text.txt - file_fullscreen-ancestor-stacking-context.html file_fullscreen-api-keys.html file_fullscreen-api.html file_fullscreen-denied-inner.html diff --git a/dom/html/test/test_fullscreen-api.html b/dom/html/test/test_fullscreen-api.html index 7397c7e1eceb..5fba7db34fa2 100644 --- a/dom/html/test/test_fullscreen-api.html +++ b/dom/html/test/test_fullscreen-api.html @@ -28,7 +28,6 @@ SimpleTest.requestFlakyTimeout("untriaged"); // run in an iframe, which by default will not have the allowfullscreen // attribute set, so full-screen won't work. var gTestWindows = [ - "file_fullscreen-ancestor-stacking-context.html", "file_fullscreen-multiple.html", "file_fullscreen-rollback.html", "file_fullscreen-esc-context-menu.html", diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index bfd3ead0b721..0ee6c0607070 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -2239,11 +2239,6 @@ nsDocumentViewer::CreateStyleSet(nsIDocument* aDocument, } } - sheet = nsLayoutStylesheetCache::FullScreenOverrideSheet(); - if (sheet) { - styleSet->PrependStyleSheet(nsStyleSet::eOverrideSheet, sheet); - } - if (!aDocument->IsSVGDocument()) { // !!! IMPORTANT - KEEP THIS BLOCK IN SYNC WITH // !!! SVGDocument::EnsureNonSVGUserAgentStyleSheetsLoaded. diff --git a/layout/style/full-screen-override.css b/layout/style/full-screen-override.css deleted file mode 100644 index 2358f35bb482..000000000000 --- a/layout/style/full-screen-override.css +++ /dev/null @@ -1,26 +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/. */ - - -*|*:-moz-full-screen-ancestor { - /* Ancestors of a full-screen element should not induce stacking contexts - that would prevent the full-screen element from being on top. */ - z-index: initial !important; - /* Ancestors of a full-screen element should not be partially transparent, - since that would apply to the full-screen element and make the page visible - behind it. It would also create a pseudo-stacking-context that would let content - draw on top of the full-screen element. */ - opacity: initial !important; - /* Ancestors of a full-screen element should not apply SVG masking, clipping, or - filtering, since that would affect the full-screen element and create a pseudo- - stacking context. */ - mask: initial !important; - clip-path: initial !important; - filter: initial !important; - clip: initial !important; - transform: initial !important; - transform-style: initial !important; - /* FIXME: do we need to worry about 'overflow'? */ - will-change: initial !important; -} diff --git a/layout/style/jar.mn b/layout/style/jar.mn index 296210c82614..73d6054a0074 100644 --- a/layout/style/jar.mn +++ b/layout/style/jar.mn @@ -6,7 +6,6 @@ toolkit.jar: * res/ua.css (ua.css) * res/html.css (html.css) res/quirk.css (quirk.css) - res/full-screen-override.css (full-screen-override.css) res/plaintext.css (plaintext.css) res/viewsource.css (viewsource.css) res/counterstyles.css (counterstyles.css) diff --git a/layout/style/nsLayoutStylesheetCache.cpp b/layout/style/nsLayoutStylesheetCache.cpp index 1f50c9fa6563..6be1df8391f2 100644 --- a/layout/style/nsLayoutStylesheetCache.cpp +++ b/layout/style/nsLayoutStylesheetCache.cpp @@ -157,13 +157,6 @@ nsLayoutStylesheetCache::QuirkSheet() return gStyleCache->mQuirkSheet; } -CSSStyleSheet* -nsLayoutStylesheetCache::FullScreenOverrideSheet() -{ - EnsureGlobal(); - return gStyleCache->mFullScreenOverrideSheet; -} - CSSStyleSheet* nsLayoutStylesheetCache::SVGSheet() { @@ -316,7 +309,6 @@ nsLayoutStylesheetCache::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf MEASURE(mCounterStylesSheet); MEASURE(mDesignModeSheet); MEASURE(mFormsSheet); - MEASURE(mFullScreenOverrideSheet); MEASURE(mHTMLSheet); MEASURE(mMathMLSheet); MEASURE(mMinimalXULSheet); @@ -357,8 +349,6 @@ nsLayoutStylesheetCache::nsLayoutStylesheetCache() // per-profile, since they're profile-invariant. LoadSheetURL("resource://gre-resources/counterstyles.css", mCounterStylesSheet, true); - LoadSheetURL("resource://gre-resources/full-screen-override.css", - mFullScreenOverrideSheet, true); LoadSheetURL("chrome://global/content/minimal-xul.css", mMinimalXULSheet, true); LoadSheetURL("resource://gre-resources/quirk.css", diff --git a/layout/style/nsLayoutStylesheetCache.h b/layout/style/nsLayoutStylesheetCache.h index 0802c3c77978..5d9beb8f90c8 100644 --- a/layout/style/nsLayoutStylesheetCache.h +++ b/layout/style/nsLayoutStylesheetCache.h @@ -44,7 +44,6 @@ class nsLayoutStylesheetCache final static mozilla::CSSStyleSheet* MinimalXULSheet(); static mozilla::CSSStyleSheet* XULSheet(); static mozilla::CSSStyleSheet* QuirkSheet(); - static mozilla::CSSStyleSheet* FullScreenOverrideSheet(); static mozilla::CSSStyleSheet* SVGSheet(); static mozilla::CSSStyleSheet* MathMLSheet(); static mozilla::CSSStyleSheet* CounterStylesSheet(); @@ -92,7 +91,6 @@ private: nsRefPtr mCounterStylesSheet; nsRefPtr mDesignModeSheet; nsRefPtr mFormsSheet; - nsRefPtr mFullScreenOverrideSheet; nsRefPtr mHTMLSheet; nsRefPtr mMathMLSheet; nsRefPtr mMinimalXULSheet; From ccd57823e923b20dc15fe085156a100c942e2a5f Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Wed, 7 Oct 2015 14:04:32 +1100 Subject: [PATCH 121/228] Bug 1126230 part 10 - Add test for fullscreen top layer. r=dbaron --HG-- extra : source : 565db2ee35652291d8d502301f50da22fb87cddd --- dom/html/test/file_fullscreen-top-layer.html | 176 +++++++++++++++++++ dom/html/test/mochitest.ini | 1 + dom/html/test/test_fullscreen-api.html | 3 +- 3 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 dom/html/test/file_fullscreen-top-layer.html diff --git a/dom/html/test/file_fullscreen-top-layer.html b/dom/html/test/file_fullscreen-top-layer.html new file mode 100644 index 000000000000..9d3e9ef594c5 --- /dev/null +++ b/dom/html/test/file_fullscreen-top-layer.html @@ -0,0 +1,176 @@ + + + + + Test for Bug 1126230 + + + + + + + +Mozilla Bug 1126230 +
+
+
+
+ + + + + + + + + diff --git a/dom/html/test/mochitest.ini b/dom/html/test/mochitest.ini index 48a74440e52c..bdfbcd37ec33 100644 --- a/dom/html/test/mochitest.ini +++ b/dom/html/test/mochitest.ini @@ -62,6 +62,7 @@ support-files = file_fullscreen-scrollbar.html file_fullscreen-selector.html file_fullscreen-svg-element.html + file_fullscreen-top-layer.html file_fullscreen-utils.js file_iframe_sandbox_a_if1.html file_iframe_sandbox_a_if10.html diff --git a/dom/html/test/test_fullscreen-api.html b/dom/html/test/test_fullscreen-api.html index 5fba7db34fa2..6a3e3df7de08 100644 --- a/dom/html/test/test_fullscreen-api.html +++ b/dom/html/test/test_fullscreen-api.html @@ -40,7 +40,8 @@ var gTestWindows = [ "file_fullscreen-svg-element.html", "file_fullscreen-navigation.html", "file_fullscreen-scrollbar.html", - "file_fullscreen-selector.html" + "file_fullscreen-selector.html", + "file_fullscreen-top-layer.html" ]; var testWindow = null; From 6aee8950752da7d539119c35f7f472446bf785ee Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Tue, 6 Oct 2015 20:52:26 -0700 Subject: [PATCH 122/228] Bug 1210905 followup: Restore accidentally-removed 'subproperties' list on -moz-transform-style in style-system mochitest file property_database.js. (no review) --- layout/style/test/property_database.js | 1 + 1 file changed, 1 insertion(+) diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js index a7bed8b8762a..c278370e7b6c 100644 --- a/layout/style/test/property_database.js +++ b/layout/style/test/property_database.js @@ -4301,6 +4301,7 @@ var gCSSProperties = { inherited: false, type: CSS_TYPE_SHORTHAND_AND_LONGHAND, alias_for: "transform-style", + subproperties: [ "transform-style" ], }, "-moz-border-image": { domProp: "MozBorderImage", From 86cc43f3749f4b66ce46108fab356f9511082618 Mon Sep 17 00:00:00 2001 From: "L. David Baron" Date: Tue, 6 Oct 2015 20:56:43 -0700 Subject: [PATCH 123/228] Bug 837211 - Add -webkit prefixed aliases for various CSS properties, behind an off-by-default preference. r=bzbarsky Note that this does not emulate the WebKit quirk of supporting element.style["-webkit-animation"] or supporting the uppercase element.style.WebkitAnimation (etc.) as opposed to the lowercase (and enumerable) element.style.webkitAnimation. Note that this also does not add aliases for transition or animation events. (Patch has been minorly tweaked by dholbert, with dbaron's approval.) --- layout/style/nsCSSParser.cpp | 2 + layout/style/nsCSSPropAliasList.h | 135 ++++++++++++++++++++++++++++++ modules/libpref/init/all.js | 3 + 3 files changed, 140 insertions(+) diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index d181698c6cce..ff2aeb5182dc 100644 --- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -3004,6 +3004,8 @@ CSSParserImpl::ParseAtRule(RuleAppendFunc aAppendFunc, } else if ((nsCSSProps::IsEnabled(eCSSPropertyAlias_MozAnimation, PropertyEnabledState()) && mToken.mIdent.LowerCaseEqualsLiteral("-moz-keyframes")) || + (nsCSSProps::IsEnabled(eCSSPropertyAlias_WebkitAnimation) && + mToken.mIdent.LowerCaseEqualsLiteral("-webkit-keyframes")) || mToken.mIdent.LowerCaseEqualsLiteral("keyframes")) { parseFunc = &CSSParserImpl::ParseKeyframesRule; newSection = eCSSSection_General; diff --git a/layout/style/nsCSSPropAliasList.h b/layout/style/nsCSSPropAliasList.h index 768c20026665..36041ea3d565 100644 --- a/layout/style/nsCSSPropAliasList.h +++ b/layout/style/nsCSSPropAliasList.h @@ -179,3 +179,138 @@ CSS_PROP_ALIAS(-moz-hyphens, hyphens, MozHyphens, "") + +#define WEBKIT_PREFIX_PREF "layout.css.prefixes.webkit" + +// -webkit- prefixes +CSS_PROP_ALIAS(-webkit-animation, + animation, + WebkitAnimation, + WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-animation-delay, + animation_delay, + WebkitAnimationDelay, + WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-animation-direction, + animation_direction, + WebkitAnimationDirection, + WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-animation-duration, + animation_duration, + WebkitAnimationDuration, + WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-animation-fill-mode, + animation_fill_mode, + WebkitAnimationFillMode, + WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-animation-iteration-count, + animation_iteration_count, + WebkitAnimationIterationCount, + WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-animation-name, + animation_name, + WebkitAnimationName, + WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-animation-play-state, + animation_play_state, + WebkitAnimationPlayState, + WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-animation-timing-function, + animation_timing_function, + WebkitAnimationTimingFunction, + WEBKIT_PREFIX_PREF) + +CSS_PROP_ALIAS(-webkit-text-size-adjust, + text_size_adjust, + WebkitTextSizeAdjust, + WEBKIT_PREFIX_PREF) + +CSS_PROP_ALIAS(-webkit-transform, + transform, + WebkitTransform, + WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-transform-origin, + transform_origin, + WebkitTransformOrigin, + WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-transform-style, + transform_style, + WebkitTransformStyle, + WEBKIT_PREFIX_PREF) + +CSS_PROP_ALIAS(-webkit-transition, + transition, + WebkitTransition, + WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-transition-delay, + transition_delay, + WebkitTransitionDelay, + WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-transition-duration, + transition_duration, + WebkitTransitionDuration, + WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-transition-property, + transition_property, + WebkitTransitionProperty, + WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-transition-timing-function, + transition_timing_function, + WebkitTransitionTimingFunction, + WEBKIT_PREFIX_PREF) + +CSS_PROP_ALIAS(-webkit-border-radius, + border_radius, + WebkitBorderRadius, + WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-border-top-left-radius, + border_top_left_radius, + WebkitBorderTopLeftRadius, // really no dom property + WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-border-top-right-radius, + border_top_right_radius, + WebkitBorderTopRightRadius, // really no dom property + WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-border-bottom-left-radius, + border_bottom_left_radius, + WebkitBorderBottomLeftRadius, // really no dom property + WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-border-bottom-right-radius, + border_bottom_right_radius, + WebkitBorderBottomRightRadius, // really no dom property + WEBKIT_PREFIX_PREF) + +CSS_PROP_ALIAS(-webkit-appearance, + appearance, + WebkitAppearance, + WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-background-clip, + background_clip, + WebkitBackgroundClip, + WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-background-origin, + background_origin, + WebkitBackgroundOrigin, + WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-background-size, + background_size, + WebkitBackgroundSize, + WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-border-image, + border_image, + WebkitBorderImage, + WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-box-shadow, + box_shadow, + WebkitBoxShadow, + WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-box-sizing, + box_sizing, + WebkitBoxSizing, + WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-user-select, + user_select, + WebkitUserSelect, + WEBKIT_PREFIX_PREF) + +#undef WEBKIT_PREFIX_PREF diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 0da1a2682957..7789ca03b74a 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -2298,6 +2298,9 @@ pref("layout.css.prefixes.box-sizing", true); pref("layout.css.prefixes.font-features", true); pref("layout.css.prefixes.gradients", true); +// Are webkit-prefixed properties & property-values supported? +pref("layout.css.prefixes.webkit", false); + // Is the CSS Unprefixing Service enabled? (This service emulates support // for certain vendor-prefixed properties & values, for sites on a "fixlist".) pref("layout.css.unprefixing-service.enabled", true); From 1925f7ca093798c236c89e3655c2578fdcd1fa54 Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Tue, 6 Oct 2015 20:56:45 -0700 Subject: [PATCH 124/228] Bug 1211101 part 1: Fix existing style system mochitests to accomodate webkit-prefixed property aliases. r=heycam --- layout/style/test/test_bug1112014.html | 8 ++++++++ layout/style/test/test_property_database.html | 4 ++++ .../style/test/test_unprefixing_service.html | 7 ++++++- .../test/test_unprefixing_service_prefs.html | 8 ++++++-- layout/style/test/test_value_computation.html | 5 +++++ layout/style/test/test_value_storage.html | 20 ++++++++++++++++++- 6 files changed, 48 insertions(+), 4 deletions(-) diff --git a/layout/style/test/test_bug1112014.html b/layout/style/test/test_bug1112014.html index e0de32d8cce8..27461f016e7b 100644 --- a/layout/style/test/test_bug1112014.html +++ b/layout/style/test/test_bug1112014.html @@ -47,10 +47,18 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1112014 TYPE_LENGTH: "url(/somewhere) 30% / 30px stretch", TYPE_IMAGE_RECT: testValues.TYPE_IMAGE_RECT + " 30 30 stretch" }, + "-webkit-border-image": { + TYPE_LENGTH: "url(/somewhere) 30% / 30px stretch", + TYPE_IMAGE_RECT: testValues.TYPE_IMAGE_RECT + " 30 30 stretch" + }, "box-shadow": { TYPE_LENGTH: "2px 2px", TYPE_COLOR: testValues.TYPE_COLOR + " 2px 2px" }, + "-webkit-box-shadow": { + TYPE_LENGTH: "2px 2px", + TYPE_COLOR: testValues.TYPE_COLOR + " 2px 2px" + }, "text-shadow": { TYPE_LENGTH: "2px 2px", TYPE_COLOR: testValues.TYPE_COLOR + " 2px 2px" diff --git a/layout/style/test/test_property_database.html b/layout/style/test/test_property_database.html index 4ab2ee4e2ed0..e8c1b37e5c09 100644 --- a/layout/style/test/test_property_database.html +++ b/layout/style/test/test_property_database.html @@ -157,6 +157,10 @@ for (var prop in gCSSProperties) { }); if (expectedDOMProp == "float") { expectedDOMProp = "cssFloat"; + } else if (prop.startsWith("-webkit")) { + // Our DOM accessors for webkit-prefixed properties start with lowercase w, + // not uppercase like standard DOM accessors. + expectedDOMProp = expectedDOMProp.replace(/^W/, "w"); } is(entry.domProp, expectedDOMProp, "DOM property for " + prop); } diff --git a/layout/style/test/test_unprefixing_service.html b/layout/style/test/test_unprefixing_service.html index 82bdbd81d196..c489e2ac01fa 100644 --- a/layout/style/test/test_unprefixing_service.html +++ b/layout/style/test/test_unprefixing_service.html @@ -76,7 +76,12 @@ function begin() // Turn on prefs & start the first test! SpecialPowers.pushPrefEnv( { set: [[PREF_UNPREFIXING_SERVICE, true], - [PREF_INCLUDE_TEST_DOMAINS, true]]}, + [PREF_INCLUDE_TEST_DOMAINS, true], + // Make sure *native* -webkit prefix support is turned off. It's + // not whitelist-restricted, so if we left it enabled, it'd prevent + // us from being able to detect CSSUnprefixingService's domain + // whitelisting in this test. + ["layout.css.prefixes.webkit", false]]}, startNextTest); } diff --git a/layout/style/test/test_unprefixing_service_prefs.html b/layout/style/test/test_unprefixing_service_prefs.html index b3a4c161ec1a..329dce2a6346 100644 --- a/layout/style/test/test_unprefixing_service_prefs.html +++ b/layout/style/test/test_unprefixing_service_prefs.html @@ -120,8 +120,12 @@ function begin() testHost(WHITELISTED_TEST_HOST, false); } -begin(); - +// Before we start, make sure *native* -webkit prefix support is turned off. +// It's not whitelist-restricted (and behaves slightly differently), so if we +// left it enabled, it'd prevent us from being able to detect +// CSSUnprefixingService's domain whitelisting in this test. +SpecialPowers.pushPrefEnv({ set: [["layout.css.prefixes.webkit", false]]}, + begin); diff --git a/layout/style/test/test_value_computation.html b/layout/style/test/test_value_computation.html index 012726bd03ab..17a59ca731e7 100644 --- a/layout/style/test/test_value_computation.html +++ b/layout/style/test/test_value_computation.html @@ -62,6 +62,11 @@ var gBadComputedNoFrame = { "border-bottom-right-radius": [ "0%", "calc(-1%)" ], "border-top-left-radius": [ "0%", "calc(-1%)" ], "border-top-right-radius": [ "0%", "calc(-1%)" ], + "-webkit-border-radius": [ "0%", "calc(-1%)", "calc(0px) calc(0pt) calc(0%) calc(0em)" ], + "-webkit-border-bottom-left-radius": [ "0%", "calc(-1%)" ], + "-webkit-border-bottom-right-radius": [ "0%", "calc(-1%)" ], + "-webkit-border-top-left-radius": [ "0%", "calc(-1%)" ], + "-webkit-border-top-right-radius": [ "0%", "calc(-1%)" ], "-moz-margin-end": [ "0%", "calc(0% + 0px)" ], "-moz-margin-start": [ "0%", "calc(0% + 0px)" ], "-moz-outline-radius": [ "0%", "calc(-1%)", "calc(0px) calc(0pt) calc(0%) calc(0em)" ], diff --git a/layout/style/test/test_value_storage.html b/layout/style/test/test_value_storage.html index 55d7bbcd2dec..16f15f1d570d 100644 --- a/layout/style/test/test_value_storage.html +++ b/layout/style/test/test_value_storage.html @@ -91,6 +91,22 @@ var gComputedStyle = window.getComputedStyle(gElement, ""); var gPrereqDeclaration = document.getElementById("prereqsheet").sheet.cssRules[0].style; +// Returns true if propA and propB are equivalent, considering aliasing. +// (i.e. if one is an alias of the other, or if they're both aliases of +// the same 3rd property) +function are_properties_aliased(propA, propB) +{ + // If either property is an alias, replace it with the property it aliases. + if ("alias_for" in gCSSProperties[propA]) { + propA = gCSSProperties[propA].alias_for; + } + if ("alias_for" in gCSSProperties[propB]) { + propB = gCSSProperties[propB].alias_for; + } + + return propA == propB; +} + function test_property(property) { var info = gCSSProperties[property]; @@ -112,7 +128,9 @@ function test_property(property) var shorthands = gPropertyShorthands[subprop]; for (idx in shorthands) { var sh = shorthands[idx]; - if (sh.replace("-moz-","") == property.replace("-moz-","")) continue; + if (are_properties_aliased(sh, property)) { + continue; + } is(gDeclaration.getPropertyValue(sh), "", "setting '" + value + "' on '" + property + "' (for shorthand '" + sh + "')"); } From 2b062f3d1278665541dfdb4cf135b790b1a6644f Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Tue, 6 Oct 2015 20:56:47 -0700 Subject: [PATCH 125/228] Bug 1211101 part 2: Add supported (preffed off) webkit-prefixed CSS property aliases to property_database.js, for use in mochitests. r=heycam --- layout/style/test/property_database.js | 220 +++++++++++++++++++++++++ testing/profiles/prefs_general.js | 3 + 2 files changed, 223 insertions(+) diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js index c278370e7b6c..eb36600c10c9 100644 --- a/layout/style/test/property_database.js +++ b/layout/style/test/property_database.js @@ -6338,6 +6338,226 @@ if (IsCSSPropertyPrefEnabled("layout.css.scroll-snap.enabled")) { }; } +if (IsCSSPropertyPrefEnabled("layout.css.prefixes.webkit")) { + gCSSProperties["-webkit-animation"] = { + domProp: "webkitAnimation", + inherited: false, + type: CSS_TYPE_TRUE_SHORTHAND, + alias_for: "animation", + subproperties: [ "animation-name", "animation-duration", "animation-timing-function", "animation-delay", "animation-direction", "animation-fill-mode", "animation-iteration-count", "animation-play-state" ], + }; + gCSSProperties["-webkit-animation-delay"] = { + domProp: "webkitAnimationDelay", + inherited: false, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "animation-delay", + subproperties: [ "animation-delay" ], + }; + gCSSProperties["-webkit-animation-direction"] = { + domProp: "webkitAnimationDirection", + inherited: false, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "animation-direction", + subproperties: [ "animation-direction" ], + }; + gCSSProperties["-webkit-animation-duration"] = { + domProp: "webkitAnimationDuration", + inherited: false, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "animation-duration", + subproperties: [ "animation-duration" ], + }; + gCSSProperties["-webkit-animation-fill-mode"] = { + domProp: "webkitAnimationFillMode", + inherited: false, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "animation-fill-mode", + subproperties: [ "animation-fill-mode" ], + }; + gCSSProperties["-webkit-animation-iteration-count"] = { + domProp: "webkitAnimationIterationCount", + inherited: false, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "animation-iteration-count", + subproperties: [ "animation-iteration-count" ], + }; + gCSSProperties["-webkit-animation-name"] = { + domProp: "webkitAnimationName", + inherited: false, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "animation-name", + subproperties: [ "animation-name" ], + }; + gCSSProperties["-webkit-animation-play-state"] = { + domProp: "webkitAnimationPlayState", + inherited: false, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "animation-play-state", + subproperties: [ "animation-play-state" ], + }; + gCSSProperties["-webkit-animation-timing-function"] = { + domProp: "webkitAnimationTimingFunction", + inherited: false, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "animation-timing-function", + subproperties: [ "animation-timing-function" ], + }; + gCSSProperties["-webkit-text-size-adjust"] = { + domProp: "webkitTextSizeAdjust", + inherited: true, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "-moz-text-size-adjust", + subproperties: [ "-moz-text-size-adjust" ], + }; + gCSSProperties["-webkit-transform"] = { + domProp: "webkitTransform", + inherited: false, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "transform", + subproperties: [ "transform" ], + }; + gCSSProperties["-webkit-transform-origin"] = { + domProp: "webkitTransformOrigin", + inherited: false, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "transform-origin", + subproperties: [ "transform-origin" ], + }; + gCSSProperties["-webkit-transform-style"] = { + domProp: "webkitTransformStyle", + inherited: false, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "transform-style", + subproperties: [ "transform-style" ], + }; + gCSSProperties["-webkit-transition"] = { + domProp: "webkitTransition", + inherited: false, + type: CSS_TYPE_TRUE_SHORTHAND, + alias_for: "transition", + subproperties: [ "transition-property", "transition-duration", "transition-timing-function", "transition-delay" ], + }; + gCSSProperties["-webkit-transition-delay"] = { + domProp: "webkitTransitionDelay", + inherited: false, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "transition-delay", + subproperties: [ "transition-delay" ], + }; + gCSSProperties["-webkit-transition-duration"] = { + domProp: "webkitTransitionDuration", + inherited: false, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "transition-duration", + subproperties: [ "transition-duration" ], + }; + gCSSProperties["-webkit-transition-property"] = { + domProp: "webkitTransitionProperty", + inherited: false, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "transition-property", + subproperties: [ "transition-property" ], + }; + gCSSProperties["-webkit-transition-timing-function"] = { + domProp: "webkitTransitionTimingFunction", + inherited: false, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "transition-timing-function", + subproperties: [ "transition-timing-function" ], + }; + gCSSProperties["-webkit-border-radius"] = { + domProp: "webkitBorderRadius", + inherited: false, + type: CSS_TYPE_TRUE_SHORTHAND, + alias_for: "border-radius", + subproperties: [ "border-bottom-left-radius", "border-bottom-right-radius", "border-top-left-radius", "border-top-right-radius" ], + }; + gCSSProperties["-webkit-border-top-left-radius"] = { + domProp: "webkitBorderTopLeftRadius", + inherited: false, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "border-top-left-radius", + subproperties: [ "border-top-left-radius" ], + }; + gCSSProperties["-webkit-border-top-right-radius"] = { + domProp: "webkitBorderTopRightRadius", + inherited: false, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "border-top-right-radius", + subproperties: [ "border-top-right-radius" ], + }; + gCSSProperties["-webkit-border-bottom-left-radius"] = { + domProp: "webkitBorderBottomLeftRadius", + inherited: false, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "border-bottom-left-radius", + subproperties: [ "border-bottom-left-radius" ], + }; + gCSSProperties["-webkit-border-bottom-right-radius"] = { + domProp: "webkitBorderBottomRightRadius", + inherited: false, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "border-bottom-right-radius", + subproperties: [ "border-bottom-right-radius" ], + }; + gCSSProperties["-webkit-appearance"] = { + domProp: "webkitAppearance", + inherited: false, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "-moz-appearance", + subproperties: [ "-moz-appearance" ], + }; + gCSSProperties["-webkit-background-clip"] = { + domProp: "webkitBackgroundClip", + inherited: false, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "background-clip", + subproperties: [ "background-clip" ], + }; + gCSSProperties["-webkit-background-origin"] = { + domProp: "webkitBackgroundOrigin", + inherited: false, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "background-origin", + subproperties: [ "background-origin" ], + }; + gCSSProperties["-webkit-background-size"] = { + domProp: "webkitBackgroundSize", + inherited: false, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "background-size", + subproperties: [ "background-size" ], + }; + gCSSProperties["-webkit-border-image"] = { + domProp: "webkitBorderImage", + inherited: false, + type: CSS_TYPE_TRUE_SHORTHAND, + alias_for: "border-image", + subproperties: [ "border-image-source", "border-image-slice", "border-image-width", "border-image-outset", "border-image-repeat" ], + }; + gCSSProperties["-webkit-box-shadow"] = { + domProp: "webkitBoxShadow", + inherited: false, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "box-shadow", + subproperties: [ "box-shadow" ], + }; + gCSSProperties["-webkit-box-sizing"] = { + domProp: "webkitBoxSizing", + inherited: false, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "box-sizing", + subproperties: [ "box-sizing" ], + }; + gCSSProperties["-webkit-user-select"] = { + domProp: "webkitUserSelect", + inherited: false, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "-moz-user-select", + subproperties: [ "-moz-user-select" ], + }; +} + if (IsCSSPropertyPrefEnabled("layout.css.unset-value.enabled")) { gCSSProperties["animation"].invalid_values.push("2s unset"); gCSSProperties["animation-direction"].invalid_values.push("normal, unset", "unset, normal"); diff --git a/testing/profiles/prefs_general.js b/testing/profiles/prefs_general.js index bcf0004aafd3..cbcd62669021 100644 --- a/testing/profiles/prefs_general.js +++ b/testing/profiles/prefs_general.js @@ -161,6 +161,9 @@ user_pref("layout.css.ruby.enabled", true); // Enable unicode-range for testing user_pref("layout.css.unicode-range.enabled", true); +// Enable webkit prefixed CSS features for testing +user_pref("layout.css.prefixes.webkit", true); + // Disable spammy layout warnings because they pollute test logs user_pref("layout.spammy_warnings.enabled", false); From 08a8534ec0039c6aeb17d506fb083c520cf94c8c Mon Sep 17 00:00:00 2001 From: Brian Birtles Date: Wed, 7 Oct 2015 14:30:27 +0900 Subject: [PATCH 126/228] Bug 1208385 part 0 - Fix up some references to Web Animations spec; r=heycam --- dom/animation/Animation.cpp | 16 +++++++++++----- dom/animation/KeyframeEffect.cpp | 5 +++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/dom/animation/Animation.cpp b/dom/animation/Animation.cpp index 648caee0485c..deb5d6894273 100644 --- a/dom/animation/Animation.cpp +++ b/dom/animation/Animation.cpp @@ -86,6 +86,7 @@ Animation::SetTimeline(AnimationTimeline* aTimeline) // (but *not* when this method gets called from style). } +// https://w3c.github.io/web-animations/#set-the-animation-start-time void Animation::SetStartTime(const Nullable& aNewStartTime) { @@ -121,7 +122,7 @@ Animation::SetStartTime(const Nullable& aNewStartTime) PostUpdate(); } -// http://w3c.github.io/web-animations/#current-time +// https://w3c.github.io/web-animations/#current-time Nullable Animation::GetCurrentTime() const { @@ -141,7 +142,7 @@ Animation::GetCurrentTime() const return result; } -// Implements http://w3c.github.io/web-animations/#set-the-current-time +// https://w3c.github.io/web-animations/#set-the-current-time void Animation::SetCurrentTime(const TimeDuration& aSeekTime) { @@ -162,6 +163,7 @@ Animation::SetCurrentTime(const TimeDuration& aSeekTime) PostUpdate(); } +// https://w3c.github.io/web-animations/#set-the-animation-playback-rate void Animation::SetPlaybackRate(double aPlaybackRate) { @@ -172,6 +174,7 @@ Animation::SetPlaybackRate(double aPlaybackRate) } } +// https://w3c.github.io/web-animations/#play-state AnimationPlayState Animation::PlayState() const { @@ -295,6 +298,7 @@ Animation::Pause(ErrorResult& aRv) PostUpdate(); } +// https://w3c.github.io/web-animations/#reverse-an-animation void Animation::Reverse(ErrorResult& aRv) { @@ -446,7 +450,7 @@ Animation::GetCurrentOrPendingStartTime() const return result; } -// http://w3c.github.io/web-animations/#silently-set-the-current-time +// https://w3c.github.io/web-animations/#silently-set-the-current-time void Animation::SilentlySetCurrentTime(const TimeDuration& aSeekTime) { @@ -477,6 +481,7 @@ Animation::SilentlySetPlaybackRate(double aPlaybackRate) } } +// https://w3c.github.io/web-animations/#cancel-an-animation void Animation::DoCancel() { @@ -662,7 +667,7 @@ Animation::NotifyEffectTimingUpdated() Animation::SyncNotifyFlag::Async); } -// http://w3c.github.io/web-animations/#play-an-animation +// https://w3c.github.io/web-animations/#play-an-animation void Animation::DoPlay(ErrorResult& aRv, LimitBehavior aLimitBehavior) { @@ -737,7 +742,7 @@ Animation::DoPlay(ErrorResult& aRv, LimitBehavior aLimitBehavior) UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async); } -// http://w3c.github.io/web-animations/#pause-an-animation +// https://w3c.github.io/web-animations/#pause-an-animation void Animation::DoPause(ErrorResult& aRv) { @@ -848,6 +853,7 @@ Animation::UpdateTiming(SeekFlag aSeekFlag, SyncNotifyFlag aSyncNotifyFlag) } } +// https://w3c.github.io/web-animations/#update-an-animations-finished-state void Animation::UpdateFinishedState(SeekFlag aSeekFlag, SyncNotifyFlag aSyncNotifyFlag) diff --git a/dom/animation/KeyframeEffect.cpp b/dom/animation/KeyframeEffect.cpp index 6cd503fe2198..3f40d930e1d2 100644 --- a/dom/animation/KeyframeEffect.cpp +++ b/dom/animation/KeyframeEffect.cpp @@ -304,7 +304,7 @@ KeyframeEffectReadOnly::ActiveDuration(const AnimationTiming& aTiming) aTiming.mIterationDuration.MultDouble(aTiming.mIterationCount)); } -// http://w3c.github.io/web-animations/#in-play +// https://w3c.github.io/web-animations/#in-play bool KeyframeEffectReadOnly::IsInPlay(const Animation& aAnimation) const { @@ -315,7 +315,7 @@ KeyframeEffectReadOnly::IsInPlay(const Animation& aAnimation) const return GetComputedTiming().mPhase == ComputedTiming::AnimationPhase_Active; } -// http://w3c.github.io/web-animations/#current +// https://w3c.github.io/web-animations/#current bool KeyframeEffectReadOnly::IsCurrent(const Animation& aAnimation) const { @@ -328,6 +328,7 @@ KeyframeEffectReadOnly::IsCurrent(const Animation& aAnimation) const computedTiming.mPhase == ComputedTiming::AnimationPhase_Active; } +// https://w3c.github.io/web-animations/#in-effect bool KeyframeEffectReadOnly::IsInEffect() const { From d89f0d836b5cd3b3465605f738190f3254918289 Mon Sep 17 00:00:00 2001 From: Brian Birtles Date: Wed, 7 Oct 2015 14:30:27 +0900 Subject: [PATCH 127/228] Bug 1208385 part 1 - Store a pointer to the owning animation on each KeyframeEffect; r=heycam We need to do this so effects can query their owning animation for the current time and avoid falling out of sync. Furthermore, this pointer is needed for a number of other bugs (e.g. bug 1166500 comment 12, or bug 1190235) anyway. --- dom/animation/Animation.cpp | 4 ++++ dom/animation/Animation.h | 4 ++-- dom/animation/KeyframeEffect.cpp | 30 +++++++++++++++++++++-------- dom/animation/KeyframeEffect.h | 20 ++++++++++--------- layout/style/AnimationCommon.cpp | 2 +- layout/style/nsAnimationManager.cpp | 2 +- 6 files changed, 41 insertions(+), 21 deletions(-) diff --git a/dom/animation/Animation.cpp b/dom/animation/Animation.cpp index deb5d6894273..69abf268744c 100644 --- a/dom/animation/Animation.cpp +++ b/dom/animation/Animation.cpp @@ -51,14 +51,18 @@ Animation::WrapObject(JSContext* aCx, JS::Handle aGivenProto) void Animation::SetEffect(KeyframeEffectReadOnly* aEffect) { + nsRefPtr kungFuDeathGrip(this); + if (mEffect == aEffect) { return; } if (mEffect) { + mEffect->SetAnimation(nullptr); mEffect->SetParentTime(Nullable()); } mEffect = aEffect; if (mEffect) { + mEffect->SetAnimation(this); mEffect->SetParentTime(GetCurrentTime()); } diff --git a/dom/animation/Animation.h b/dom/animation/Animation.h index 33c55e7eabaa..53a10053fdfb 100644 --- a/dom/animation/Animation.h +++ b/dom/animation/Animation.h @@ -238,11 +238,11 @@ public: bool HasInPlayEffect() const { - return GetEffect() && GetEffect()->IsInPlay(*this); + return GetEffect() && GetEffect()->IsInPlay(); } bool HasCurrentEffect() const { - return GetEffect() && GetEffect()->IsCurrent(*this); + return GetEffect() && GetEffect()->IsCurrent(); } bool IsInEffect() const { diff --git a/dom/animation/KeyframeEffect.cpp b/dom/animation/KeyframeEffect.cpp index 3f40d930e1d2..a6fd342fc1fa 100644 --- a/dom/animation/KeyframeEffect.cpp +++ b/dom/animation/KeyframeEffect.cpp @@ -109,7 +109,8 @@ namespace dom { NS_IMPL_CYCLE_COLLECTION_INHERITED(KeyframeEffectReadOnly, AnimationEffectReadOnly, - mTarget) + mTarget, + mAnimation) NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(KeyframeEffectReadOnly, AnimationEffectReadOnly) @@ -149,14 +150,15 @@ KeyframeEffectReadOnly::SetParentTime(Nullable aParentTime) } void -KeyframeEffectReadOnly::SetTiming(const AnimationTiming& aTiming, - Animation& aOwningAnimation) +KeyframeEffectReadOnly::SetTiming(const AnimationTiming& aTiming) { if (mTiming == aTiming) { return; } mTiming = aTiming; - aOwningAnimation.NotifyEffectTimingUpdated(); + if (mAnimation) { + mAnimation->NotifyEffectTimingUpdated(); + } } ComputedTiming @@ -306,9 +308,9 @@ KeyframeEffectReadOnly::ActiveDuration(const AnimationTiming& aTiming) // https://w3c.github.io/web-animations/#in-play bool -KeyframeEffectReadOnly::IsInPlay(const Animation& aAnimation) const +KeyframeEffectReadOnly::IsInPlay() const { - if (aAnimation.PlayState() == AnimationPlayState::Finished) { + if (!mAnimation || mAnimation->PlayState() == AnimationPlayState::Finished) { return false; } @@ -317,9 +319,9 @@ KeyframeEffectReadOnly::IsInPlay(const Animation& aAnimation) const // https://w3c.github.io/web-animations/#current bool -KeyframeEffectReadOnly::IsCurrent(const Animation& aAnimation) const +KeyframeEffectReadOnly::IsCurrent() const { - if (aAnimation.PlayState() == AnimationPlayState::Finished) { + if (!mAnimation || mAnimation->PlayState() == AnimationPlayState::Finished) { return false; } @@ -336,6 +338,12 @@ KeyframeEffectReadOnly::IsInEffect() const return computedTiming.mProgress != ComputedTiming::kNullProgress; } +void +KeyframeEffectReadOnly::SetAnimation(Animation* aAnimation) +{ + mAnimation = aAnimation; +} + const AnimationProperty* KeyframeEffectReadOnly::GetAnimationOfProperty(nsCSSProperty aProperty) const { @@ -495,6 +503,12 @@ KeyframeEffectReadOnly::SetIsRunningOnCompositor(nsCSSProperty aProperty, } } +// We need to define this here since Animation is an incomplete type +// (forward-declared) in the header. +KeyframeEffectReadOnly::~KeyframeEffectReadOnly() +{ +} + void KeyframeEffectReadOnly::ResetIsRunningOnCompositor() { diff --git a/dom/animation/KeyframeEffect.h b/dom/animation/KeyframeEffect.h index 191e3309469a..d726573a5355 100644 --- a/dom/animation/KeyframeEffect.h +++ b/dom/animation/KeyframeEffect.h @@ -202,6 +202,8 @@ struct ElementPropertyTransition; namespace dom { +class Animation; + class KeyframeEffectReadOnly : public AnimationEffectReadOnly { public: @@ -253,10 +255,7 @@ public: AnimationTiming& Timing() { return mTiming; } - - // FIXME: Drop |aOwningAnimation| once we make AnimationEffects track their - // owning animation. - void SetTiming(const AnimationTiming& aTiming, Animation& aOwningAnimtion); + void SetTiming(const AnimationTiming& aTiming); Nullable GetLocalTime() const { // Since the *animation* start time is currently always zero, the local @@ -289,10 +288,12 @@ public: static StickyTimeDuration ActiveDuration(const AnimationTiming& aTiming); - bool IsInPlay(const Animation& aAnimation) const; - bool IsCurrent(const Animation& aAnimation) const; + bool IsInPlay() const; + bool IsCurrent() const; bool IsInEffect() const; + void SetAnimation(Animation* aAnimation); + const AnimationProperty* GetAnimationOfProperty(nsCSSProperty aProperty) const; bool HasAnimationOfProperty(nsCSSProperty aProperty) const { @@ -308,8 +309,8 @@ public: } // Updates |aStyleRule| with the animation values produced by this - // Animation for the current time except any properties already contained - // in |aSetProperties|. + // AnimationEffect for the current time except any properties already + // contained in |aSetProperties|. // Any updated properties are added to |aSetProperties|. void ComposeStyle(nsRefPtr& aStyleRule, nsCSSPropertySet& aSetProperties); @@ -317,10 +318,11 @@ public: void SetIsRunningOnCompositor(nsCSSProperty aProperty, bool aIsRunning); protected: - virtual ~KeyframeEffectReadOnly() { } + virtual ~KeyframeEffectReadOnly(); void ResetIsRunningOnCompositor(); nsCOMPtr mTarget; + nsRefPtr mAnimation; Nullable mParentTime; AnimationTiming mTiming; diff --git a/layout/style/AnimationCommon.cpp b/layout/style/AnimationCommon.cpp index c57510cadf1a..ff4583484da1 100644 --- a/layout/style/AnimationCommon.cpp +++ b/layout/style/AnimationCommon.cpp @@ -915,7 +915,7 @@ AnimationCollection::HasCurrentAnimationsForProperties( const Animation& anim = *mAnimations[animIdx]; const KeyframeEffectReadOnly* effect = anim.GetEffect(); if (effect && - effect->IsCurrent(anim) && + effect->IsCurrent() && effect->HasAnimationOfProperties(aProperties, aPropertyCount)) { return true; } diff --git a/layout/style/nsAnimationManager.cpp b/layout/style/nsAnimationManager.cpp index 101822801ec2..a411568d150f 100644 --- a/layout/style/nsAnimationManager.cpp +++ b/layout/style/nsAnimationManager.cpp @@ -505,7 +505,7 @@ nsAnimationManager::CheckAnimationRule(nsStyleContext* aStyleContext, animationChanged = oldEffect->Timing() != newEffect->Timing() || oldEffect->Properties() != newEffect->Properties(); - oldEffect->SetTiming(newEffect->Timing(), *oldAnim); + oldEffect->SetTiming(newEffect->Timing()); oldEffect->Properties() = newEffect->Properties(); } From ad657213b13185489eb3a2f0981c924c54258eb9 Mon Sep 17 00:00:00 2001 From: Brian Birtles Date: Wed, 7 Oct 2015 14:30:28 +0900 Subject: [PATCH 128/228] Bug 1208385 part 2 - Remove stored parent time from KeyframeEffectReadOnly and get the time directly from the owning animation; r=heycam --- dom/animation/Animation.cpp | 3 --- dom/animation/KeyframeEffect.cpp | 18 ++++++++++++------ dom/animation/KeyframeEffect.h | 9 +-------- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/dom/animation/Animation.cpp b/dom/animation/Animation.cpp index 69abf268744c..e201877b9ba9 100644 --- a/dom/animation/Animation.cpp +++ b/dom/animation/Animation.cpp @@ -58,12 +58,10 @@ Animation::SetEffect(KeyframeEffectReadOnly* aEffect) } if (mEffect) { mEffect->SetAnimation(nullptr); - mEffect->SetParentTime(Nullable()); } mEffect = aEffect; if (mEffect) { mEffect->SetAnimation(this); - mEffect->SetParentTime(GetCurrentTime()); } UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async); @@ -912,7 +910,6 @@ void Animation::UpdateEffect() { if (mEffect) { - mEffect->SetParentTime(GetCurrentTime()); UpdateRelevance(); } } diff --git a/dom/animation/KeyframeEffect.cpp b/dom/animation/KeyframeEffect.cpp index a6fd342fc1fa..a12ed98098bf 100644 --- a/dom/animation/KeyframeEffect.cpp +++ b/dom/animation/KeyframeEffect.cpp @@ -143,12 +143,6 @@ KeyframeEffectReadOnly::WrapObject(JSContext* aCx, return KeyframeEffectReadOnlyBinding::Wrap(aCx, this, aGivenProto); } -void -KeyframeEffectReadOnly::SetParentTime(Nullable aParentTime) -{ - mParentTime = aParentTime; -} - void KeyframeEffectReadOnly::SetTiming(const AnimationTiming& aTiming) { @@ -161,6 +155,18 @@ KeyframeEffectReadOnly::SetTiming(const AnimationTiming& aTiming) } } +Nullable +KeyframeEffectReadOnly::GetLocalTime() const +{ + // Since the *animation* start time is currently always zero, the local + // time is equal to the parent time. + Nullable result; + if (mAnimation) { + result = mAnimation->GetCurrentTime(); + } + return result; +} + ComputedTiming KeyframeEffectReadOnly::GetComputedTimingAt( const Nullable& aLocalTime, diff --git a/dom/animation/KeyframeEffect.h b/dom/animation/KeyframeEffect.h index d726573a5355..2e09a2aab243 100644 --- a/dom/animation/KeyframeEffect.h +++ b/dom/animation/KeyframeEffect.h @@ -247,8 +247,6 @@ public: aPseudoType = mPseudoType; } - void SetParentTime(Nullable aParentTime); - const AnimationTiming& Timing() const { return mTiming; } @@ -257,11 +255,7 @@ public: } void SetTiming(const AnimationTiming& aTiming); - Nullable GetLocalTime() const { - // Since the *animation* start time is currently always zero, the local - // time is equal to the parent time. - return mParentTime; - } + Nullable GetLocalTime() const; // This function takes as input the timing parameters of an animation and // returns the computed timing at the specified local time. @@ -323,7 +317,6 @@ protected: nsCOMPtr mTarget; nsRefPtr mAnimation; - Nullable mParentTime; AnimationTiming mTiming; nsCSSPseudoElements::Type mPseudoType; From 9590e60a48337d3843580bf54c2cce964ac6f5ea Mon Sep 17 00:00:00 2001 From: Brian Birtles Date: Thu, 17 Sep 2015 15:43:15 +0900 Subject: [PATCH 129/228] Bug 1208938 part 1 - Rename AnimationCollection::mNeedsRefreshes to mStyleChanging; r=heycam This patch renames AnimationCollection::mNeedsRefreshes to indicate that it no longer has any relationship to whether or not we observe the refresh driver. --- dom/animation/Animation.cpp | 4 ++-- dom/animation/Animation.h | 4 ++-- layout/style/AnimationCommon.cpp | 10 +++++----- layout/style/AnimationCommon.h | 4 ++-- layout/style/nsAnimationManager.cpp | 2 +- layout/style/nsTransitionManager.cpp | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/dom/animation/Animation.cpp b/dom/animation/Animation.cpp index e201877b9ba9..b5646be53b92 100644 --- a/dom/animation/Animation.cpp +++ b/dom/animation/Animation.cpp @@ -573,7 +573,7 @@ Animation::CanThrottle() const void Animation::ComposeStyle(nsRefPtr& aStyleRule, nsCSSPropertySet& aSetProperties, - bool& aNeedsRefreshes) + bool& aStyleChanging) { if (!mEffect) { return; @@ -583,7 +583,7 @@ Animation::ComposeStyle(nsRefPtr& aStyleRule, if (playState == AnimationPlayState::Running || playState == AnimationPlayState::Pending || HasEndEventToQueue()) { - aNeedsRefreshes = true; + aStyleChanging = true; } if (!IsInEffect()) { diff --git a/dom/animation/Animation.h b/dom/animation/Animation.h index 53a10053fdfb..1bb2bbe4b35b 100644 --- a/dom/animation/Animation.h +++ b/dom/animation/Animation.h @@ -285,13 +285,13 @@ public: * if any. * Any properties already contained in |aSetProperties| are not changed. Any * properties that are changed are added to |aSetProperties|. - * |aNeedsRefreshes| will be set to true if this animation expects to update + * |aStyleChanging| will be set to true if this animation expects to update * the style rule on the next refresh driver tick as well (because it * is running and has an effect to sample). */ void ComposeStyle(nsRefPtr& aStyleRule, nsCSSPropertySet& aSetProperties, - bool& aNeedsRefreshes); + bool& aStyleChanging); // FIXME: Because we currently determine if we need refresh driver ticks diff --git a/layout/style/AnimationCommon.cpp b/layout/style/AnimationCommon.cpp index ff4583484da1..74d70476a555 100644 --- a/layout/style/AnimationCommon.cpp +++ b/layout/style/AnimationCommon.cpp @@ -697,7 +697,7 @@ AnimationCollection::EnsureStyleRuleFor(TimeStamp aRefreshTime) { mHasPendingAnimationRestyle = false; - if (!mNeedsRefreshes) { + if (!mStyleChanging) { mStyleRuleRefreshTime = aRefreshTime; return; } @@ -716,8 +716,8 @@ AnimationCollection::EnsureStyleRuleFor(TimeStamp aRefreshTime) mStyleRuleRefreshTime = aRefreshTime; mStyleRule = nullptr; - // We'll set mNeedsRefreshes to true below in all cases where we need them. - mNeedsRefreshes = false; + // We'll set mStyleChanging to true below if necessary. + mStyleChanging = false; // If multiple animations specify behavior for the same property the // animation which occurs last in the value of animation-name wins. @@ -726,7 +726,7 @@ AnimationCollection::EnsureStyleRuleFor(TimeStamp aRefreshTime) nsCSSPropertySet properties; for (size_t animIdx = mAnimations.Length(); animIdx-- != 0; ) { - mAnimations[animIdx]->ComposeStyle(mStyleRule, properties, mNeedsRefreshes); + mAnimations[animIdx]->ComposeStyle(mStyleRule, properties, mStyleChanging); } } @@ -842,7 +842,7 @@ AnimationCollection::RequestRestyle(RestyleType aRestyleType) if (aRestyleType == RestyleType::Layer) { mStyleRuleRefreshTime = TimeStamp(); - mNeedsRefreshes = true; + mStyleChanging = true; // Prompt layers to re-sync their animations. presContext->ClearLastStyleUpdateForAllAnimations(); diff --git a/layout/style/AnimationCommon.h b/layout/style/AnimationCommon.h index 1da88cd6633d..a002dcd22f3b 100644 --- a/layout/style/AnimationCommon.h +++ b/layout/style/AnimationCommon.h @@ -213,7 +213,7 @@ struct AnimationCollection : public LinkedListElement , mManager(aManager) , mAnimationGeneration(0) , mCheckGeneration(0) - , mNeedsRefreshes(true) + , mStyleChanging(true) , mHasPendingAnimationRestyle(false) #ifdef DEBUG , mCalledPropertyDtor(false) @@ -410,7 +410,7 @@ public: // False when we know that our current style rule is valid // indefinitely into the future (because all of our animations are // either completed or paused). May be invalidated by a style change. - bool mNeedsRefreshes; + bool mStyleChanging; private: // Whether or not we have already posted for animation restyle. diff --git a/layout/style/nsAnimationManager.cpp b/layout/style/nsAnimationManager.cpp index a411568d150f..f88c6a0231c9 100644 --- a/layout/style/nsAnimationManager.cpp +++ b/layout/style/nsAnimationManager.cpp @@ -561,7 +561,7 @@ nsAnimationManager::CheckAnimationRule(nsStyleContext* aStyleContext, } } collection->mAnimations.SwapElements(newAnimations); - collection->mNeedsRefreshes = true; + collection->mStyleChanging = true; // Cancel removed animations for (size_t newAnimIdx = newAnimations.Length(); newAnimIdx-- != 0; ) { diff --git a/layout/style/nsTransitionManager.cpp b/layout/style/nsTransitionManager.cpp index 7e895103ea55..2fa364f6f318 100644 --- a/layout/style/nsTransitionManager.cpp +++ b/layout/style/nsTransitionManager.cpp @@ -487,7 +487,7 @@ nsTransitionManager::StyleContextChanged(dom::Element *aElement, // creates a new style rule if we started *or* stopped transitions. collection->mStyleRuleRefreshTime = TimeStamp(); collection->UpdateCheckGeneration(mPresContext); - collection->mNeedsRefreshes = true; + collection->mStyleChanging = true; TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh(); collection->EnsureStyleRuleFor(now); } From 0ea5e5c7c888d39f80a658eaf58636db08cc1536 Mon Sep 17 00:00:00 2001 From: Brian Birtles Date: Wed, 7 Oct 2015 14:30:28 +0900 Subject: [PATCH 130/228] Bug 1208938 part 2 - Remove Animation::HasEndEventToQueue; r=heycam --- dom/animation/Animation.cpp | 3 +-- dom/animation/Animation.h | 13 ------------- layout/style/nsAnimationManager.cpp | 15 --------------- layout/style/nsAnimationManager.h | 1 - layout/style/nsTransitionManager.cpp | 11 ----------- layout/style/nsTransitionManager.h | 1 - 6 files changed, 1 insertion(+), 43 deletions(-) diff --git a/dom/animation/Animation.cpp b/dom/animation/Animation.cpp index b5646be53b92..a4c37303b344 100644 --- a/dom/animation/Animation.cpp +++ b/dom/animation/Animation.cpp @@ -581,8 +581,7 @@ Animation::ComposeStyle(nsRefPtr& aStyleRule, AnimationPlayState playState = PlayState(); if (playState == AnimationPlayState::Running || - playState == AnimationPlayState::Pending || - HasEndEventToQueue()) { + playState == AnimationPlayState::Pending) { aStyleChanging = true; } diff --git a/dom/animation/Animation.h b/dom/animation/Animation.h index 1bb2bbe4b35b..4798d66d20ad 100644 --- a/dom/animation/Animation.h +++ b/dom/animation/Animation.h @@ -293,19 +293,6 @@ public: nsCSSPropertySet& aSetProperties, bool& aStyleChanging); - - // FIXME: Because we currently determine if we need refresh driver ticks - // during restyling (specifically ComposeStyle above) and not necessarily - // during a refresh driver tick, we can arrive at a situation where we - // have finished running an animation but are waiting until the next tick - // to queue the final end event. This method tells us when we are in that - // situation so we can avoid unregistering from the refresh driver until - // we've finished dispatching events. - // - // This is a temporary measure until bug 1195180 is done and we can do all - // our registering and unregistering within a tick callback. - virtual bool HasEndEventToQueue() const { return false; } - void NotifyEffectTimingUpdated(); protected: diff --git a/layout/style/nsAnimationManager.cpp b/layout/style/nsAnimationManager.cpp index f88c6a0231c9..400853e35205 100644 --- a/layout/style/nsAnimationManager.cpp +++ b/layout/style/nsAnimationManager.cpp @@ -275,21 +275,6 @@ CSSAnimation::QueueEvents() this)); } -bool -CSSAnimation::HasEndEventToQueue() const -{ - if (!mEffect) { - return false; - } - - bool wasActive = mPreviousPhaseOrIteration != PREVIOUS_PHASE_BEFORE && - mPreviousPhaseOrIteration != PREVIOUS_PHASE_AFTER; - bool isActive = mEffect->GetComputedTiming().mPhase == - ComputedTiming::AnimationPhase_Active; - - return wasActive && !isActive; -} - CommonAnimationManager* CSSAnimation::GetAnimationManager() const { diff --git a/layout/style/nsAnimationManager.h b/layout/style/nsAnimationManager.h index d16ef4f918e7..dfd87ad387fb 100644 --- a/layout/style/nsAnimationManager.h +++ b/layout/style/nsAnimationManager.h @@ -126,7 +126,6 @@ public: void Tick() override; void QueueEvents(); - bool HasEndEventToQueue() const override; bool IsStylePaused() const { return mIsStylePaused; } diff --git a/layout/style/nsTransitionManager.cpp b/layout/style/nsTransitionManager.cpp index 2fa364f6f318..d23b6a7278e6 100644 --- a/layout/style/nsTransitionManager.cpp +++ b/layout/style/nsTransitionManager.cpp @@ -155,17 +155,6 @@ CSSTransition::QueueEvents() this)); } -bool -CSSTransition::HasEndEventToQueue() const -{ - if (!mEffect) { - return false; - } - - return !mWasFinishedOnLastTick && - PlayState() == AnimationPlayState::Finished; -} - void CSSTransition::Tick() { diff --git a/layout/style/nsTransitionManager.h b/layout/style/nsTransitionManager.h index 6351c3340b32..487e6f7fa13c 100644 --- a/layout/style/nsTransitionManager.h +++ b/layout/style/nsTransitionManager.h @@ -164,7 +164,6 @@ protected: SyncNotifyFlag aSyncNotifyFlag) override; void QueueEvents(); - bool HasEndEventToQueue() const override; // The (pseudo-)element whose computed transition-property refers to this // transition (if any). From 6b03b4a52fd3c691101f4ed05d64ab5f9861fb97 Mon Sep 17 00:00:00 2001 From: Brian Birtles Date: Wed, 7 Oct 2015 14:30:28 +0900 Subject: [PATCH 131/228] Bug 1208938 part 3 - Update pending finishing handling; r=heycam Animation::Tick contains special handling to cope with pending ready times that are in the future. This was originally introduced to cope with the situation where we are called multiple times per refresh-driver tick. As of bug 1195180, Animation::Tick should no longer be called multiple times per refresh driver tick. It would seem, therefore, that we no longer need to check for a future time. However, since introducing this check, the vsync refresh driver timer has been added which means that we can still have a recorded time from TimeStamp::Now that is ahead of the vsync time used to update the refresh driver. In that case, however, rather than waiting for the next tick, we should simply clamp that pending ready time to the refresh driver time and finish pending immediately. This patch also updates one of the tests for reversing. With this updated behavior we can sometimes arrive at a situation where when an Animation starts and its ready promise resolves, its currentTime is still 0. If we call reverse() at this point on an animation with an infinite active duration it should throw an InvalidStateError. To avoid this situation, this test makes sure we wait an extra frame before calling reverse(). --- dom/animation/Animation.cpp | 15 +++++++++------ .../css-animations/file_animation-reverse.html | 6 +++++- dom/animation/test/testcommon.js | 3 ++- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/dom/animation/Animation.cpp b/dom/animation/Animation.cpp index a4c37303b344..fc187adb79b6 100644 --- a/dom/animation/Animation.cpp +++ b/dom/animation/Animation.cpp @@ -360,15 +360,18 @@ Animation::SetCurrentTimeAsDouble(const Nullable& aCurrentTime, void Animation::Tick() { - // Since we are not guaranteed to get only one call per refresh driver tick, - // it's possible that mPendingReadyTime is set to a time in the future. - // In that case, we should wait until the next refresh driver tick before - // resuming. + // Finish pending if we have a pending ready time, but only if we also + // have an active timeline. if (mPendingState != PendingState::NotPending && !mPendingReadyTime.IsNull() && mTimeline && - !mTimeline->GetCurrentTime().IsNull() && - mPendingReadyTime.Value() <= mTimeline->GetCurrentTime().Value()) { + !mTimeline->GetCurrentTime().IsNull()) { + // Even though mPendingReadyTime is initialized using TimeStamp::Now() + // during the *previous* tick of the refresh driver, it can still be + // ahead of the *current* timeline time when we are using the + // vsync timer so we need to clamp it to the timeline time. + mPendingReadyTime.SetValue(std::min(mTimeline->GetCurrentTime().Value(), + mPendingReadyTime.Value())); FinishPendingAt(mPendingReadyTime.Value()); mPendingReadyTime.SetNull(); } diff --git a/dom/animation/test/css-animations/file_animation-reverse.html b/dom/animation/test/css-animations/file_animation-reverse.html index c217471cb028..037ffd2c703a 100644 --- a/dom/animation/test/css-animations/file_animation-reverse.html +++ b/dom/animation/test/css-animations/file_animation-reverse.html @@ -14,7 +14,11 @@ async_test(function(t) { var div = addDiv(t, { style: 'animation: anim 100s infinite' }); var animation = div.getAnimations()[0]; - animation.ready.then(t.step_func_done(function() { + // Wait a frame because if currentTime is still 0 when we call + // reverse(), it will throw (per spec). + animation.ready.then(waitForFrame).then(t.step_func_done(function() { + assert_greater_than(animation.currentTime, 0, + 'currentTime expected to be greater than 0, one frame after starting'); var previousPlaybackRate = animation.playbackRate; animation.reverse(); assert_equals(animation.playbackRate, -previousPlaybackRate, diff --git a/dom/animation/test/testcommon.js b/dom/animation/test/testcommon.js index f44e8de3d3c7..ec2f6d226c9d 100644 --- a/dom/animation/test/testcommon.js +++ b/dom/animation/test/testcommon.js @@ -92,7 +92,8 @@ function flushComputedStyle(elem) { if (opener) { for (var funcName of ["async_test", "assert_not_equals", "assert_equals", "assert_approx_equals", "assert_less_than", - "assert_less_than_equal", "assert_between_inclusive", + "assert_less_than_equal", "assert_greater_than", + "assert_between_inclusive", "assert_true", "assert_false", "assert_class_string", "assert_throws", "assert_unreached", "test"]) { From 3a86e96468673270ec1816a522bd6e51ed51b536 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Tue, 6 Oct 2015 11:59:47 +1100 Subject: [PATCH 132/228] Bug 1211652: Add sourcebuffer.mode = sequence mochitest. r=gerald --- dom/media/mediasource/test/mochitest.ini | 2 + .../mediasource/test/test_Sequence_mp4.html | 39 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 dom/media/mediasource/test/test_Sequence_mp4.html diff --git a/dom/media/mediasource/test/mochitest.ini b/dom/media/mediasource/test/mochitest.ini index 0005ff4e41b6..2d990ce0b9b7 100644 --- a/dom/media/mediasource/test/mochitest.ini +++ b/dom/media/mediasource/test/mochitest.ini @@ -78,6 +78,8 @@ skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+ [test_SeekTwice_mp4.html] skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+ +[test_Sequence_mp4.html] +skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+ [test_SetModeThrows.html] [test_SplitAppendDelay.html] [test_SplitAppendDelay_mp4.html] diff --git a/dom/media/mediasource/test/test_Sequence_mp4.html b/dom/media/mediasource/test/test_Sequence_mp4.html new file mode 100644 index 000000000000..f0542438d9a1 --- /dev/null +++ b/dom/media/mediasource/test/test_Sequence_mp4.html @@ -0,0 +1,39 @@ + + + + MSE: Don't get stuck buffering for too long when we have frames to show + + + + + +

+
+ + From 89639edfde9448794ac04785f1a0f47d28c5266e Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Tue, 6 Oct 2015 22:55:18 +1100 Subject: [PATCH 133/228] Bug 1211335: Have FFMpegDecoderModule properly return if a codec is supported. r=cpearce --- .../platforms/ffmpeg/FFmpegDataDecoder.cpp | 28 +++++++++++-------- .../platforms/ffmpeg/FFmpegDataDecoder.h | 2 ++ .../platforms/ffmpeg/FFmpegDecoderModule.h | 9 ++++-- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp index 6079c8673be4..84e4c24f6add 100644 --- a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp @@ -70,24 +70,16 @@ ChoosePixelFormat(AVCodecContext* aCodecContext, const PixelFormat* aFormats) nsresult FFmpegDataDecoder::InitDecoder() { - StaticMutexAutoLock mon(sMonitor); - FFMPEG_LOG("Initialising FFmpeg decoder."); - if (!sFFmpegInitDone) { - avcodec_register_all(); -#ifdef DEBUG - av_log_set_level(AV_LOG_DEBUG); -#endif - sFFmpegInitDone = true; - } - - AVCodec* codec = avcodec_find_decoder(mCodecID); + AVCodec* codec = FindAVCodec(mCodecID); if (!codec) { NS_WARNING("Couldn't find ffmpeg decoder"); return NS_ERROR_FAILURE; } + StaticMutexAutoLock mon(sMonitor); + if (!(mCodecContext = avcodec_alloc_context3(codec))) { NS_WARNING("Couldn't init ffmpeg context"); return NS_ERROR_FAILURE; @@ -240,4 +232,18 @@ FFmpegDataDecoder::PrepareFrame() return mFrame; } +/* static */ AVCodec* +FFmpegDataDecoder::FindAVCodec(AVCodecID aCodec) +{ + StaticMutexAutoLock mon(sMonitor); + if (!sFFmpegInitDone) { + avcodec_register_all(); +#ifdef DEBUG + av_log_set_level(AV_LOG_DEBUG); +#endif + sFFmpegInitDone = true; + } + return avcodec_find_decoder(aCodec); +} + } // namespace mozilla diff --git a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.h b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.h index 9b7cfb124839..c8f98e0835ea 100644 --- a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.h +++ b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.h @@ -36,6 +36,8 @@ public: nsresult Drain() override; nsresult Shutdown() override; + static AVCodec* FindAVCodec(AVCodecID aCodec); + protected: // Flush and Drain operation, always run virtual void ProcessFlush(); diff --git a/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h b/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h index 0e99695d205d..24322d2da541 100644 --- a/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h +++ b/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h @@ -68,8 +68,13 @@ public: bool SupportsMimeType(const nsACString& aMimeType) override { - return FFmpegAudioDecoder::GetCodecId(aMimeType) != AV_CODEC_ID_NONE || - FFmpegH264Decoder::GetCodecId(aMimeType) != AV_CODEC_ID_NONE; + AVCodecID audioCodec = FFmpegAudioDecoder::GetCodecId(aMimeType); + AVCodecID videoCodec = FFmpegH264Decoder::GetCodecId(aMimeType); + if (audioCodec == AV_CODEC_ID_NONE && videoCodec == AV_CODEC_ID_NONE) { + return false; + } + AVCodecID codec = audioCodec != AV_CODEC_ID_NONE ? audioCodec : videoCodec; + return !!FFmpegDataDecoder::FindAVCodec(codec); } ConversionRequired From 9586070ed3754a47f69238696c0dfa2ee762aa57 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Mon, 5 Oct 2015 18:59:24 +1100 Subject: [PATCH 134/228] Bug 1206977: P1. Remove unused PDM function members. r=cpearce --- dom/media/platforms/PlatformDecoderModule.h | 4 ---- dom/media/platforms/agnostic/BlankDecoderModule.cpp | 5 ----- 2 files changed, 9 deletions(-) diff --git a/dom/media/platforms/PlatformDecoderModule.h b/dom/media/platforms/PlatformDecoderModule.h index bd633f6b4e30..4bebc973ac49 100644 --- a/dom/media/platforms/PlatformDecoderModule.h +++ b/dom/media/platforms/PlatformDecoderModule.h @@ -110,10 +110,6 @@ public: // feeding it to MediaDataDecoder::Input. virtual ConversionRequired DecoderNeedsConversion(const TrackInfo& aConfig) const = 0; - virtual bool SupportsSharedDecoders(const VideoInfo& aConfig) const { - return !AgnosticMimeType(aConfig.mMimeType); - } - protected: PlatformDecoderModule() {} virtual ~PlatformDecoderModule() {} diff --git a/dom/media/platforms/agnostic/BlankDecoderModule.cpp b/dom/media/platforms/agnostic/BlankDecoderModule.cpp index b6a77f6298bd..f176055f59dc 100644 --- a/dom/media/platforms/agnostic/BlankDecoderModule.cpp +++ b/dom/media/platforms/agnostic/BlankDecoderModule.cpp @@ -251,11 +251,6 @@ public: return true; } - bool - SupportsSharedDecoders(const VideoInfo& aConfig) const override { - return false; - } - ConversionRequired DecoderNeedsConversion(const TrackInfo& aConfig) const override { From 025699316455ce441d5a6671c5914e7ca762071a Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Mon, 5 Oct 2015 21:08:56 +1100 Subject: [PATCH 135/228] Bug 1206977: P2. Wrap PDM creation in a new PDMFactory class. r=cpearce There is no change of behaviour from the original PlatformDecoderModule. --- dom/media/MediaFormatReader.cpp | 6 +- dom/media/platforms/PDMFactory.cpp | 244 ++++++++++++++++++ dom/media/platforms/PDMFactory.h | 80 ++++++ dom/media/platforms/PlatformDecoderModule.cpp | 226 +--------------- dom/media/platforms/PlatformDecoderModule.h | 24 +- .../platforms/ffmpeg/FFmpegDecoderModule.h | 3 +- .../platforms/ffmpeg/FFmpegRuntimeLinker.cpp | 6 + .../platforms/ffmpeg/FFmpegRuntimeLinker.h | 2 + dom/media/platforms/moz.build | 1 + 9 files changed, 346 insertions(+), 246 deletions(-) create mode 100644 dom/media/platforms/PDMFactory.cpp create mode 100644 dom/media/platforms/PDMFactory.h diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp index be12573a1c8d..527c84141639 100644 --- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -239,15 +239,13 @@ MediaFormatReader::IsWaitingOnCDMResource() { bool MediaFormatReader::IsSupportedAudioMimeType(const nsACString& aMimeType) { - return mPlatform && (mPlatform->SupportsMimeType(aMimeType) || - PlatformDecoderModule::AgnosticMimeType(aMimeType)); + return mPlatform && mPlatform->SupportsMimeType(aMimeType); } bool MediaFormatReader::IsSupportedVideoMimeType(const nsACString& aMimeType) { - return mPlatform && (mPlatform->SupportsMimeType(aMimeType) || - PlatformDecoderModule::AgnosticMimeType(aMimeType)); + return mPlatform && mPlatform->SupportsMimeType(aMimeType); } nsRefPtr diff --git a/dom/media/platforms/PDMFactory.cpp b/dom/media/platforms/PDMFactory.cpp new file mode 100644 index 000000000000..a2e5f23d64e2 --- /dev/null +++ b/dom/media/platforms/PDMFactory.cpp @@ -0,0 +1,244 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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 "PDMFactory.h" + +#ifdef XP_WIN +#include "WMFDecoderModule.h" +#endif +#ifdef MOZ_FFMPEG +#include "FFmpegRuntimeLinker.h" +#endif +#ifdef MOZ_APPLEMEDIA +#include "AppleDecoderModule.h" +#endif +#ifdef MOZ_GONK_MEDIACODEC +#include "GonkDecoderModule.h" +#endif +#ifdef MOZ_WIDGET_ANDROID +#include "AndroidDecoderModule.h" +#endif +#include "GMPDecoderModule.h" + +#include "mozilla/Preferences.h" +#include "mozilla/TaskQueue.h" + +#include "mozilla/SharedThreadPool.h" + +#include "MediaInfo.h" +#include "FuzzingWrapper.h" +#include "H264Converter.h" + +#include "OpusDecoder.h" +#include "VorbisDecoder.h" +#include "VPXDecoder.h" + +namespace mozilla { + +extern already_AddRefed CreateAgnosticDecoderModule(); +extern already_AddRefed CreateBlankDecoderModule(); + +bool PDMFactory::sUseBlankDecoder = false; +bool PDMFactory::sGonkDecoderEnabled = false; +bool PDMFactory::sAndroidMCDecoderEnabled = false; +bool PDMFactory::sAndroidMCDecoderPreferred = false; +bool PDMFactory::sGMPDecoderEnabled = false; +bool PDMFactory::sEnableFuzzingWrapper = false; +uint32_t PDMFactory::sVideoOutputMinimumInterval_ms = 0; +bool PDMFactory::sDontDelayInputExhausted = false; + +/* static */ +void +PDMFactory::Init() +{ + MOZ_ASSERT(NS_IsMainThread()); + static bool alreadyInitialized = false; + if (alreadyInitialized) { + return; + } + alreadyInitialized = true; + + Preferences::AddBoolVarCache(&sUseBlankDecoder, + "media.fragmented-mp4.use-blank-decoder"); +#ifdef MOZ_GONK_MEDIACODEC + Preferences::AddBoolVarCache(&sGonkDecoderEnabled, + "media.fragmented-mp4.gonk.enabled", false); +#endif +#ifdef MOZ_WIDGET_ANDROID + Preferences::AddBoolVarCache(&sAndroidMCDecoderEnabled, + "media.fragmented-mp4.android-media-codec.enabled", false); + Preferences::AddBoolVarCache(&sAndroidMCDecoderPreferred, + "media.fragmented-mp4.android-media-codec.preferred", false); +#endif + + Preferences::AddBoolVarCache(&sGMPDecoderEnabled, + "media.fragmented-mp4.gmp.enabled", false); + + Preferences::AddBoolVarCache(&sEnableFuzzingWrapper, + "media.decoder.fuzzing.enabled", false); + Preferences::AddUintVarCache(&sVideoOutputMinimumInterval_ms, + "media.decoder.fuzzing.video-output-minimum-interval-ms", 0); + Preferences::AddBoolVarCache(&sDontDelayInputExhausted, + "media.decoder.fuzzing.dont-delay-inputexhausted", false); + +#ifdef XP_WIN + WMFDecoderModule::Init(); +#endif +#ifdef MOZ_APPLEMEDIA + AppleDecoderModule::Init(); +#endif +#ifdef MOZ_FFMPEG + FFmpegRuntimeLinker::Link(); +#endif +} + +PDMFactory::PDMFactory() + : mCurrentPDM(CreatePDM()) +{ + if (!mCurrentPDM || NS_FAILED(mCurrentPDM->Startup())) { + mCurrentPDM = CreateAgnosticDecoderModule(); + } +} + +PDMFactory::~PDMFactory() +{ +} + +already_AddRefed +PDMFactory::CreateDecoder(const TrackInfo& aConfig, + FlushableTaskQueue* aTaskQueue, + MediaDataDecoderCallback* aCallback, + layers::LayersBackend aLayersBackend, + layers::ImageContainer* aImageContainer) +{ + MOZ_ASSERT(mCurrentPDM); + + nsRefPtr m; + + bool hasPlatformDecoder = mCurrentPDM->SupportsMimeType(aConfig.mMimeType); + + if (aConfig.GetAsAudioInfo()) { + if (!hasPlatformDecoder && VorbisDataDecoder::IsVorbis(aConfig.mMimeType)) { + m = new VorbisDataDecoder(*aConfig.GetAsAudioInfo(), + aTaskQueue, + aCallback); + } else if (!hasPlatformDecoder && OpusDataDecoder::IsOpus(aConfig.mMimeType)) { + m = new OpusDataDecoder(*aConfig.GetAsAudioInfo(), + aTaskQueue, + aCallback); + } else { + m = mCurrentPDM->CreateAudioDecoder(*aConfig.GetAsAudioInfo(), + aTaskQueue, + aCallback); + } + return m.forget(); + } + + if (!aConfig.GetAsVideoInfo()) { + return nullptr; + } + + MediaDataDecoderCallback* callback = aCallback; + nsRefPtr callbackWrapper; + if (sEnableFuzzingWrapper) { + callbackWrapper = new DecoderCallbackFuzzingWrapper(aCallback); + callbackWrapper->SetVideoOutputMinimumInterval( + TimeDuration::FromMilliseconds(sVideoOutputMinimumInterval_ms)); + callbackWrapper->SetDontDelayInputExhausted(sDontDelayInputExhausted); + callback = callbackWrapper.get(); + } + + if (H264Converter::IsH264(aConfig)) { + nsRefPtr h + = new H264Converter(mCurrentPDM, + *aConfig.GetAsVideoInfo(), + aLayersBackend, + aImageContainer, + aTaskQueue, + callback); + const nsresult rv = h->GetLastError(); + if (NS_SUCCEEDED(rv) || rv == NS_ERROR_NOT_INITIALIZED) { + // The H264Converter either successfully created the wrapped decoder, + // or there wasn't enough AVCC data to do so. Otherwise, there was some + // problem, for example WMF DLLs were missing. + m = h.forget(); + } + } else if (!hasPlatformDecoder && VPXDecoder::IsVPX(aConfig.mMimeType)) { + m = new VPXDecoder(*aConfig.GetAsVideoInfo(), + aImageContainer, + aTaskQueue, + callback); + } else { + m = mCurrentPDM->CreateVideoDecoder(*aConfig.GetAsVideoInfo(), + aLayersBackend, + aImageContainer, + aTaskQueue, + callback); + } + + if (callbackWrapper && m) { + m = new DecoderFuzzingWrapper(m.forget(), callbackWrapper.forget()); + } + + return m.forget(); +} + +bool +PDMFactory::SupportsMimeType(const nsACString& aMimeType) +{ + MOZ_ASSERT(mCurrentPDM); + return mCurrentPDM->SupportsMimeType(aMimeType) || + VPXDecoder::IsVPX(aMimeType) || + OpusDataDecoder::IsOpus(aMimeType) || + VorbisDataDecoder::IsVorbis(aMimeType); +} + +already_AddRefed +PDMFactory::CreatePDM() +{ + if (sGMPDecoderEnabled) { + nsRefPtr m(new GMPDecoderModule()); + return m.forget(); + } +#ifdef MOZ_WIDGET_ANDROID + if(sAndroidMCDecoderPreferred && sAndroidMCDecoderEnabled){ + nsRefPtr m(new AndroidDecoderModule()); + return m.forget(); + } +#endif + if (sUseBlankDecoder) { + return CreateBlankDecoderModule(); + } +#ifdef XP_WIN + nsRefPtr m(new WMFDecoderModule()); + return m.forget(); +#endif +#ifdef MOZ_FFMPEG + nsRefPtr mffmpeg = FFmpegRuntimeLinker::CreateDecoderModule(); + if (mffmpeg) { + return mffmpeg.forget(); + } +#endif +#ifdef MOZ_APPLEMEDIA + nsRefPtr m(new AppleDecoderModule()); + return m.forget(); +#endif +#ifdef MOZ_GONK_MEDIACODEC + if (sGonkDecoderEnabled) { + nsRefPtr m(new GonkDecoderModule()); + return m.forget(); + } +#endif +#ifdef MOZ_WIDGET_ANDROID + if(sAndroidMCDecoderEnabled){ + nsRefPtr m(new AndroidDecoderModule()); + return m.forget(); + } +#endif + return nullptr; +} + +} // namespace mozilla diff --git a/dom/media/platforms/PDMFactory.h b/dom/media/platforms/PDMFactory.h new file mode 100644 index 000000000000..2cd70a83bfcc --- /dev/null +++ b/dom/media/platforms/PDMFactory.h @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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/. */ + +#if !defined(PDMFactory_h_) +#define PDMFactory_h_ + +#include "PlatformDecoderModule.h" + +namespace mozilla { + +class PDMFactory : public PlatformDecoderModule { +public: + PDMFactory(); + virtual ~PDMFactory(); + + // Call on the main thread to initialize the static state + // needed by Create(). + static void Init(); + + already_AddRefed + CreateDecoder(const TrackInfo& aConfig, + FlushableTaskQueue* aTaskQueue, + MediaDataDecoderCallback* aCallback, + layers::LayersBackend aLayersBackend = layers::LayersBackend::LAYERS_NONE, + layers::ImageContainer* aImageContainer = nullptr) override; + + bool SupportsMimeType(const nsACString& aMimeType) override; + + ConversionRequired + DecoderNeedsConversion(const TrackInfo& aConfig) const override + { + MOZ_CRASH("Should never reach this function"); + return ConversionRequired::kNeedNone; + } + +protected: + // Decode thread. + already_AddRefed + CreateVideoDecoder(const VideoInfo& aConfig, + layers::LayersBackend aLayersBackend, + layers::ImageContainer* aImageContainer, + FlushableTaskQueue* aVideoTaskQueue, + MediaDataDecoderCallback* aCallback) override + { + MOZ_CRASH("Should never reach this function"); + return nullptr; + } + + // Decode thread. + already_AddRefed + CreateAudioDecoder(const AudioInfo& aConfig, + FlushableTaskQueue* aAudioTaskQueue, + MediaDataDecoderCallback* aCallback) override + { + MOZ_CRASH("Should never reach this function"); + return nullptr; + } + +private: + already_AddRefed CreatePDM(); + + // Caches pref media.fragmented-mp4.use-blank-decoder + static bool sUseBlankDecoder; + static bool sGonkDecoderEnabled; + static bool sAndroidMCDecoderPreferred; + static bool sAndroidMCDecoderEnabled; + static bool sGMPDecoderEnabled; + static bool sEnableFuzzingWrapper; + static uint32_t sVideoOutputMinimumInterval_ms; + static bool sDontDelayInputExhausted; + + nsRefPtr mCurrentPDM; +}; + +} // namespace mozilla + +#endif /* PDMFactory_h_ */ diff --git a/dom/media/platforms/PlatformDecoderModule.cpp b/dom/media/platforms/PlatformDecoderModule.cpp index 70294c9c1a0b..fdb495744f8b 100644 --- a/dom/media/platforms/PlatformDecoderModule.cpp +++ b/dom/media/platforms/PlatformDecoderModule.cpp @@ -5,40 +5,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "PlatformDecoderModule.h" - -#ifdef XP_WIN -#include "WMFDecoderModule.h" -#endif -#ifdef MOZ_FFMPEG -#include "FFmpegRuntimeLinker.h" -#endif -#ifdef MOZ_APPLEMEDIA -#include "AppleDecoderModule.h" -#endif -#ifdef MOZ_GONK_MEDIACODEC -#include "GonkDecoderModule.h" -#endif -#ifdef MOZ_WIDGET_ANDROID -#include "AndroidDecoderModule.h" -#endif -#include "GMPDecoderModule.h" - -#include "mozilla/Preferences.h" -#include "mozilla/TaskQueue.h" - +#include "PDMFactory.h" #ifdef MOZ_EME #include "EMEDecoderModule.h" #include "mozilla/CDMProxy.h" #endif -#include "mozilla/SharedThreadPool.h" - -#include "MediaInfo.h" -#include "FuzzingWrapper.h" -#include "H264Converter.h" - -#include "OpusDecoder.h" -#include "VorbisDecoder.h" -#include "VPXDecoder.h" PRLogModuleInfo* GetPDMLog() { static PRLogModuleInfo* log = nullptr; @@ -50,65 +21,12 @@ PRLogModuleInfo* GetPDMLog() { namespace mozilla { -extern already_AddRefed CreateAgnosticDecoderModule(); -extern already_AddRefed CreateBlankDecoderModule(); - -bool PlatformDecoderModule::sUseBlankDecoder = false; -bool PlatformDecoderModule::sFFmpegDecoderEnabled = false; -bool PlatformDecoderModule::sGonkDecoderEnabled = false; -bool PlatformDecoderModule::sAndroidMCDecoderEnabled = false; -bool PlatformDecoderModule::sAndroidMCDecoderPreferred = false; -bool PlatformDecoderModule::sGMPDecoderEnabled = false; -bool PlatformDecoderModule::sEnableFuzzingWrapper = false; -uint32_t PlatformDecoderModule::sVideoOutputMinimumInterval_ms = 0; -bool PlatformDecoderModule::sDontDelayInputExhausted = false; - /* static */ void PlatformDecoderModule::Init() { MOZ_ASSERT(NS_IsMainThread()); - static bool alreadyInitialized = false; - if (alreadyInitialized) { - return; - } - alreadyInitialized = true; - - Preferences::AddBoolVarCache(&sUseBlankDecoder, - "media.fragmented-mp4.use-blank-decoder"); - Preferences::AddBoolVarCache(&sFFmpegDecoderEnabled, - "media.fragmented-mp4.ffmpeg.enabled", false); - -#ifdef MOZ_GONK_MEDIACODEC - Preferences::AddBoolVarCache(&sGonkDecoderEnabled, - "media.fragmented-mp4.gonk.enabled", false); -#endif -#ifdef MOZ_WIDGET_ANDROID - Preferences::AddBoolVarCache(&sAndroidMCDecoderEnabled, - "media.fragmented-mp4.android-media-codec.enabled", false); - Preferences::AddBoolVarCache(&sAndroidMCDecoderPreferred, - "media.fragmented-mp4.android-media-codec.preferred", false); -#endif - - Preferences::AddBoolVarCache(&sGMPDecoderEnabled, - "media.fragmented-mp4.gmp.enabled", false); - - Preferences::AddBoolVarCache(&sEnableFuzzingWrapper, - "media.decoder.fuzzing.enabled", false); - Preferences::AddUintVarCache(&sVideoOutputMinimumInterval_ms, - "media.decoder.fuzzing.video-output-minimum-interval-ms", 0); - Preferences::AddBoolVarCache(&sDontDelayInputExhausted, - "media.decoder.fuzzing.dont-delay-inputexhausted", false); - -#ifdef XP_WIN - WMFDecoderModule::Init(); -#endif -#ifdef MOZ_APPLEMEDIA - AppleDecoderModule::Init(); -#endif -#ifdef MOZ_FFMPEG - FFmpegRuntimeLinker::Link(); -#endif + PDMFactory::Init(); } #ifdef MOZ_EME @@ -142,135 +60,7 @@ already_AddRefed PlatformDecoderModule::Create() { // Note: This (usually) runs on the decode thread. - - nsRefPtr m(CreatePDM()); - - if (m && NS_SUCCEEDED(m->Startup())) { - return m.forget(); - } - return CreateAgnosticDecoderModule(); -} - -/* static */ -already_AddRefed -PlatformDecoderModule::CreatePDM() -{ - if (sGMPDecoderEnabled) { - nsRefPtr m(new GMPDecoderModule()); - return m.forget(); - } -#ifdef MOZ_WIDGET_ANDROID - if(sAndroidMCDecoderPreferred && sAndroidMCDecoderEnabled){ - nsRefPtr m(new AndroidDecoderModule()); - return m.forget(); - } -#endif - if (sUseBlankDecoder) { - return CreateBlankDecoderModule(); - } -#ifdef XP_WIN - nsRefPtr m(new WMFDecoderModule()); - return m.forget(); -#endif -#ifdef MOZ_FFMPEG - nsRefPtr mffmpeg = FFmpegRuntimeLinker::CreateDecoderModule(); - if (mffmpeg) { - return mffmpeg.forget(); - } -#endif -#ifdef MOZ_APPLEMEDIA - nsRefPtr m(new AppleDecoderModule()); - return m.forget(); -#endif -#ifdef MOZ_GONK_MEDIACODEC - if (sGonkDecoderEnabled) { - nsRefPtr m(new GonkDecoderModule()); - return m.forget(); - } -#endif -#ifdef MOZ_WIDGET_ANDROID - if(sAndroidMCDecoderEnabled){ - nsRefPtr m(new AndroidDecoderModule()); - return m.forget(); - } -#endif - return nullptr; -} - -already_AddRefed -PlatformDecoderModule::CreateDecoder(const TrackInfo& aConfig, - FlushableTaskQueue* aTaskQueue, - MediaDataDecoderCallback* aCallback, - layers::LayersBackend aLayersBackend, - layers::ImageContainer* aImageContainer) -{ - nsRefPtr m; - - bool hasPlatformDecoder = SupportsMimeType(aConfig.mMimeType); - - if (aConfig.GetAsAudioInfo()) { - if (!hasPlatformDecoder && VorbisDataDecoder::IsVorbis(aConfig.mMimeType)) { - m = new VorbisDataDecoder(*aConfig.GetAsAudioInfo(), - aTaskQueue, - aCallback); - } else if (!hasPlatformDecoder && OpusDataDecoder::IsOpus(aConfig.mMimeType)) { - m = new OpusDataDecoder(*aConfig.GetAsAudioInfo(), - aTaskQueue, - aCallback); - } else { - m = CreateAudioDecoder(*aConfig.GetAsAudioInfo(), - aTaskQueue, - aCallback); - } - return m.forget(); - } - - if (!aConfig.GetAsVideoInfo()) { - return nullptr; - } - - MediaDataDecoderCallback* callback = aCallback; - nsRefPtr callbackWrapper; - if (sEnableFuzzingWrapper) { - callbackWrapper = new DecoderCallbackFuzzingWrapper(aCallback); - callbackWrapper->SetVideoOutputMinimumInterval( - TimeDuration::FromMilliseconds(sVideoOutputMinimumInterval_ms)); - callbackWrapper->SetDontDelayInputExhausted(sDontDelayInputExhausted); - callback = callbackWrapper.get(); - } - - if (H264Converter::IsH264(aConfig)) { - nsRefPtr h - = new H264Converter(this, - *aConfig.GetAsVideoInfo(), - aLayersBackend, - aImageContainer, - aTaskQueue, - callback); - const nsresult rv = h->GetLastError(); - if (NS_SUCCEEDED(rv) || rv == NS_ERROR_NOT_INITIALIZED) { - // The H264Converter either successfully created the wrapped decoder, - // or there wasn't enough AVCC data to do so. Otherwise, there was some - // problem, for example WMF DLLs were missing. - m = h.forget(); - } - } else if (!hasPlatformDecoder && VPXDecoder::IsVPX(aConfig.mMimeType)) { - m = new VPXDecoder(*aConfig.GetAsVideoInfo(), - aImageContainer, - aTaskQueue, - callback); - } else { - m = CreateVideoDecoder(*aConfig.GetAsVideoInfo(), - aLayersBackend, - aImageContainer, - aTaskQueue, - callback); - } - - if (callbackWrapper && m) { - m = new DecoderFuzzingWrapper(m.forget(), callbackWrapper.forget()); - } - + nsRefPtr m = new PDMFactory; return m.forget(); } @@ -282,14 +72,4 @@ PlatformDecoderModule::SupportsMimeType(const nsACString& aMimeType) aMimeType.EqualsLiteral("video/avc"); } -/* static */ -bool -PlatformDecoderModule::AgnosticMimeType(const nsACString& aMimeType) -{ - return VPXDecoder::IsVPX(aMimeType) || - OpusDataDecoder::IsOpus(aMimeType) || - VorbisDataDecoder::IsVorbis(aMimeType); -} - - } // namespace mozilla diff --git a/dom/media/platforms/PlatformDecoderModule.h b/dom/media/platforms/PlatformDecoderModule.h index 4bebc973ac49..e8d4426354d1 100644 --- a/dom/media/platforms/PlatformDecoderModule.h +++ b/dom/media/platforms/PlatformDecoderModule.h @@ -63,8 +63,6 @@ public: // PlatformDecoderModule created per MP4Reader. // This is called on the decode task queue. static already_AddRefed Create(); - // As Create() but do not initialize the created PlatformDecoderModule. - static already_AddRefed CreatePDM(); // Perform any per-instance initialization. // This is called on the decode task queue. @@ -87,7 +85,10 @@ public: FlushableTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, layers::LayersBackend aLayersBackend = layers::LayersBackend::LAYERS_NONE, - layers::ImageContainer* aImageContainer = nullptr); + layers::ImageContainer* aImageContainer = nullptr) + { + MOZ_CRASH(); + } // An audio decoder module must support AAC by default. // A video decoder must support H264 by default. @@ -95,10 +96,6 @@ public: // to be extended virtual bool SupportsMimeType(const nsACString& aMimeType); - // MimeType can be decoded with shipped decoders if no platform decoders exist - static bool AgnosticMimeType(const nsACString& aMimeType); - - enum ConversionRequired { kNeedNone, kNeedAVCC, @@ -115,6 +112,8 @@ protected: virtual ~PlatformDecoderModule() {} friend class H264Converter; + friend class PDMFactory; + // Creates a Video decoder. The layers backend is passed in so that // decoders can determine whether hardware accelerated decoding can be used. // Asynchronous decoding of video should be done in runnables dispatched @@ -147,17 +146,6 @@ protected: CreateAudioDecoder(const AudioInfo& aConfig, FlushableTaskQueue* aAudioTaskQueue, MediaDataDecoderCallback* aCallback) = 0; - - // Caches pref media.fragmented-mp4.use-blank-decoder - static bool sUseBlankDecoder; - static bool sFFmpegDecoderEnabled; - static bool sGonkDecoderEnabled; - static bool sAndroidMCDecoderPreferred; - static bool sAndroidMCDecoderEnabled; - static bool sGMPDecoderEnabled; - static bool sEnableFuzzingWrapper; - static uint32_t sVideoOutputMinimumInterval_ms; - static bool sDontDelayInputExhausted; }; // A callback used by MediaDataDecoder to return output/errors to the diff --git a/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h b/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h index 24322d2da541..ef9973d1ce2b 100644 --- a/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h +++ b/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h @@ -10,6 +10,7 @@ #include "PlatformDecoderModule.h" #include "FFmpegAudioDecoder.h" #include "FFmpegH264Decoder.h" +#include "FFmpegRuntimeLinker.h" namespace mozilla { @@ -23,7 +24,7 @@ public: { uint32_t major, minor; GetVersion(major, minor); - if (major < 54 && !sFFmpegDecoderEnabled) { + if (major < 54 && !FFmpegRuntimeLinker::sFFmpegDecoderEnabled) { return nullptr; } nsRefPtr pdm = new FFmpegDecoderModule(); diff --git a/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp b/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp index ca3d9fea75e0..a60851de21cd 100644 --- a/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp @@ -9,12 +9,15 @@ #include "FFmpegRuntimeLinker.h" #include "mozilla/ArrayUtils.h" #include "FFmpegLog.h" +#include "mozilla/Preferences.h" #define NUM_ELEMENTS(X) (sizeof(X) / sizeof((X)[0])) namespace mozilla { +bool FFmpegRuntimeLinker::sFFmpegDecoderEnabled = false; + FFmpegRuntimeLinker::LinkStatus FFmpegRuntimeLinker::sLinkStatus = LinkStatus_INIT; @@ -59,6 +62,9 @@ FFmpegRuntimeLinker::Link() return sLinkStatus == LinkStatus_SUCCEEDED; } + Preferences::AddBoolVarCache(&sFFmpegDecoderEnabled, + "media.fragmented-mp4.ffmpeg.enabled", false); + MOZ_ASSERT(NS_IsMainThread()); for (size_t i = 0; i < ArrayLength(sLibs); i++) { diff --git a/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.h b/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.h index 68e42f15ce64..5e098dfa1f10 100644 --- a/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.h +++ b/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.h @@ -22,6 +22,8 @@ public: static void Unlink(); static already_AddRefed CreateDecoderModule(); + static bool sFFmpegDecoderEnabled; + private: static void* sLinkedLib; static const AvCodecLib* sLib; diff --git a/dom/media/platforms/moz.build b/dom/media/platforms/moz.build index 66e17091aa07..ae84d1f0144c 100644 --- a/dom/media/platforms/moz.build +++ b/dom/media/platforms/moz.build @@ -18,6 +18,7 @@ UNIFIED_SOURCES += [ 'agnostic/OpusDecoder.cpp', 'agnostic/VorbisDecoder.cpp', 'agnostic/VPXDecoder.cpp', + 'PDMFactory.cpp', 'PlatformDecoderModule.cpp', 'wrappers/FuzzingWrapper.cpp', 'wrappers/H264Converter.cpp' From 78fc388e1e553a4b077c3c9b2e0aa972fbbc42c0 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Tue, 6 Oct 2015 09:08:03 +1100 Subject: [PATCH 136/228] Bug 1206977: P3. Allow PDM fallback. r=cpearce We now search in all the PDM present the one that can handle the media. --- dom/media/platforms/PDMFactory.cpp | 141 ++++++++++++++++------------- dom/media/platforms/PDMFactory.h | 8 +- 2 files changed, 86 insertions(+), 63 deletions(-) diff --git a/dom/media/platforms/PDMFactory.cpp b/dom/media/platforms/PDMFactory.cpp index a2e5f23d64e2..f14b8a0bd5d4 100644 --- a/dom/media/platforms/PDMFactory.cpp +++ b/dom/media/platforms/PDMFactory.cpp @@ -96,11 +96,8 @@ PDMFactory::Init() } PDMFactory::PDMFactory() - : mCurrentPDM(CreatePDM()) { - if (!mCurrentPDM || NS_FAILED(mCurrentPDM->Startup())) { - mCurrentPDM = CreateAgnosticDecoderModule(); - } + CreatePDMs(); } PDMFactory::~PDMFactory() @@ -114,25 +111,22 @@ PDMFactory::CreateDecoder(const TrackInfo& aConfig, layers::LayersBackend aLayersBackend, layers::ImageContainer* aImageContainer) { - MOZ_ASSERT(mCurrentPDM); - + nsRefPtr current = GetDecoder(aConfig.mMimeType); nsRefPtr m; - bool hasPlatformDecoder = mCurrentPDM->SupportsMimeType(aConfig.mMimeType); - if (aConfig.GetAsAudioInfo()) { - if (!hasPlatformDecoder && VorbisDataDecoder::IsVorbis(aConfig.mMimeType)) { + if (!current && VorbisDataDecoder::IsVorbis(aConfig.mMimeType)) { m = new VorbisDataDecoder(*aConfig.GetAsAudioInfo(), aTaskQueue, aCallback); - } else if (!hasPlatformDecoder && OpusDataDecoder::IsOpus(aConfig.mMimeType)) { + } else if (!current && OpusDataDecoder::IsOpus(aConfig.mMimeType)) { m = new OpusDataDecoder(*aConfig.GetAsAudioInfo(), aTaskQueue, aCallback); - } else { - m = mCurrentPDM->CreateAudioDecoder(*aConfig.GetAsAudioInfo(), - aTaskQueue, - aCallback); + } else if (current) { + m = current->CreateAudioDecoder(*aConfig.GetAsAudioInfo(), + aTaskQueue, + aCallback); } return m.forget(); } @@ -151,32 +145,34 @@ PDMFactory::CreateDecoder(const TrackInfo& aConfig, callback = callbackWrapper.get(); } - if (H264Converter::IsH264(aConfig)) { - nsRefPtr h - = new H264Converter(mCurrentPDM, - *aConfig.GetAsVideoInfo(), - aLayersBackend, - aImageContainer, - aTaskQueue, - callback); - const nsresult rv = h->GetLastError(); - if (NS_SUCCEEDED(rv) || rv == NS_ERROR_NOT_INITIALIZED) { - // The H264Converter either successfully created the wrapped decoder, - // or there wasn't enough AVCC data to do so. Otherwise, there was some - // problem, for example WMF DLLs were missing. - m = h.forget(); - } - } else if (!hasPlatformDecoder && VPXDecoder::IsVPX(aConfig.mMimeType)) { + if (!current && VPXDecoder::IsVPX(aConfig.mMimeType)) { m = new VPXDecoder(*aConfig.GetAsVideoInfo(), aImageContainer, aTaskQueue, callback); - } else { - m = mCurrentPDM->CreateVideoDecoder(*aConfig.GetAsVideoInfo(), - aLayersBackend, - aImageContainer, - aTaskQueue, - callback); + } else if (current) { + if (H264Converter::IsH264(aConfig)) { + nsRefPtr h + = new H264Converter(current, + *aConfig.GetAsVideoInfo(), + aLayersBackend, + aImageContainer, + aTaskQueue, + callback); + const nsresult rv = h->GetLastError(); + if (NS_SUCCEEDED(rv) || rv == NS_ERROR_NOT_INITIALIZED) { + // The H264Converter either successfully created the wrapped decoder, + // or there wasn't enough AVCC data to do so. Otherwise, there was some + // problem, for example WMF DLLs were missing. + m = h.forget(); + } + } else { + m = current->CreateVideoDecoder(*aConfig.GetAsVideoInfo(), + aLayersBackend, + aImageContainer, + aTaskQueue, + callback); + } } if (callbackWrapper && m) { @@ -189,56 +185,79 @@ PDMFactory::CreateDecoder(const TrackInfo& aConfig, bool PDMFactory::SupportsMimeType(const nsACString& aMimeType) { - MOZ_ASSERT(mCurrentPDM); - return mCurrentPDM->SupportsMimeType(aMimeType) || + nsRefPtr current = GetDecoder(aMimeType); + return current || VPXDecoder::IsVPX(aMimeType) || OpusDataDecoder::IsOpus(aMimeType) || VorbisDataDecoder::IsVorbis(aMimeType); } -already_AddRefed -PDMFactory::CreatePDM() +void +PDMFactory::CreatePDMs() { + nsRefPtr m; + if (sGMPDecoderEnabled) { - nsRefPtr m(new GMPDecoderModule()); - return m.forget(); + m = new GMPDecoderModule(); + StartupPDM(m); } #ifdef MOZ_WIDGET_ANDROID - if(sAndroidMCDecoderPreferred && sAndroidMCDecoderEnabled){ - nsRefPtr m(new AndroidDecoderModule()); - return m.forget(); + if(sAndroidMCDecoderPreferred && sAndroidMCDecoderEnabled) { + m = new AndroidDecoderModule(); + StartupPDM(m); } #endif - if (sUseBlankDecoder) { - return CreateBlankDecoderModule(); - } #ifdef XP_WIN - nsRefPtr m(new WMFDecoderModule()); - return m.forget(); + m = new WMFDecoderModule(); + StartupPDM(m); #endif #ifdef MOZ_FFMPEG - nsRefPtr mffmpeg = FFmpegRuntimeLinker::CreateDecoderModule(); - if (mffmpeg) { - return mffmpeg.forget(); - } + m = FFmpegRuntimeLinker::CreateDecoderModule(); + StartupPDM(m); #endif #ifdef MOZ_APPLEMEDIA - nsRefPtr m(new AppleDecoderModule()); - return m.forget(); + m = new AppleDecoderModule(); + StartupPDM(m); #endif #ifdef MOZ_GONK_MEDIACODEC if (sGonkDecoderEnabled) { - nsRefPtr m(new GonkDecoderModule()); - return m.forget(); + m = new GonkDecoderModule(); + StartupPDM(m); } #endif #ifdef MOZ_WIDGET_ANDROID if(sAndroidMCDecoderEnabled){ - nsRefPtr m(new AndroidDecoderModule()); - return m.forget(); + m = new AndroidDecoderModule(); + StartupPDM(m); } #endif - return nullptr; + if (sUseBlankDecoder) { + m = CreateBlankDecoderModule(); + StartupPDM(m); + } +} + +bool +PDMFactory::StartupPDM(PlatformDecoderModule* aPDM) +{ + if (aPDM && NS_SUCCEEDED(aPDM->Startup())) { + mCurrentPDMs.AppendElement(aPDM); + return true; + } + return false; +} + +already_AddRefed +PDMFactory::GetDecoder(const nsACString& aMimeType) +{ + nsRefPtr pdm; + for (auto& current : mCurrentPDMs) { + if (current->SupportsMimeType(aMimeType)) { + pdm = current; + break; + } + } + return pdm.forget(); } } // namespace mozilla diff --git a/dom/media/platforms/PDMFactory.h b/dom/media/platforms/PDMFactory.h index 2cd70a83bfcc..4f88f215ea4f 100644 --- a/dom/media/platforms/PDMFactory.h +++ b/dom/media/platforms/PDMFactory.h @@ -60,7 +60,11 @@ protected: } private: - already_AddRefed CreatePDM(); + void CreatePDMs(); + // Startup the provided PDM and add it to our list if successful. + bool StartupPDM(PlatformDecoderModule* aPDM); + // Returns the first PDM in our list supporting the mimetype. + already_AddRefed GetDecoder(const nsACString& aMimeType); // Caches pref media.fragmented-mp4.use-blank-decoder static bool sUseBlankDecoder; @@ -72,7 +76,7 @@ private: static uint32_t sVideoOutputMinimumInterval_ms; static bool sDontDelayInputExhausted; - nsRefPtr mCurrentPDM; + nsTArray> mCurrentPDMs; }; } // namespace mozilla From 55d1cb62fc9e21e9aed3beb2681769169e721776 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Tue, 6 Oct 2015 09:53:02 +1100 Subject: [PATCH 137/228] Bug 1206977: P4. Add AgnosticDecoderModule object. r=cpearce This removes the need for PDMFactory to know anything about decoders. --- dom/media/platforms/PDMFactory.cpp | 75 ++++++++----------- .../agnostic/AgnosticDecoderModule.cpp | 61 +++++++++++++++ .../agnostic/AgnosticDecoderModule.h | 39 ++++++++++ .../platforms/agnostic/BlankDecoderModule.cpp | 17 ----- dom/media/platforms/moz.build | 2 + 5 files changed, 132 insertions(+), 62 deletions(-) create mode 100644 dom/media/platforms/agnostic/AgnosticDecoderModule.cpp create mode 100644 dom/media/platforms/agnostic/AgnosticDecoderModule.h diff --git a/dom/media/platforms/PDMFactory.cpp b/dom/media/platforms/PDMFactory.cpp index f14b8a0bd5d4..54006762716a 100644 --- a/dom/media/platforms/PDMFactory.cpp +++ b/dom/media/platforms/PDMFactory.cpp @@ -32,9 +32,7 @@ #include "FuzzingWrapper.h" #include "H264Converter.h" -#include "OpusDecoder.h" -#include "VorbisDecoder.h" -#include "VPXDecoder.h" +#include "AgnosticDecoderModule.h" namespace mozilla { @@ -112,22 +110,15 @@ PDMFactory::CreateDecoder(const TrackInfo& aConfig, layers::ImageContainer* aImageContainer) { nsRefPtr current = GetDecoder(aConfig.mMimeType); + if (!current) { + return nullptr; + } nsRefPtr m; if (aConfig.GetAsAudioInfo()) { - if (!current && VorbisDataDecoder::IsVorbis(aConfig.mMimeType)) { - m = new VorbisDataDecoder(*aConfig.GetAsAudioInfo(), - aTaskQueue, - aCallback); - } else if (!current && OpusDataDecoder::IsOpus(aConfig.mMimeType)) { - m = new OpusDataDecoder(*aConfig.GetAsAudioInfo(), - aTaskQueue, - aCallback); - } else if (current) { - m = current->CreateAudioDecoder(*aConfig.GetAsAudioInfo(), + m = current->CreateAudioDecoder(*aConfig.GetAsAudioInfo(), aTaskQueue, aCallback); - } return m.forget(); } @@ -145,34 +136,27 @@ PDMFactory::CreateDecoder(const TrackInfo& aConfig, callback = callbackWrapper.get(); } - if (!current && VPXDecoder::IsVPX(aConfig.mMimeType)) { - m = new VPXDecoder(*aConfig.GetAsVideoInfo(), - aImageContainer, - aTaskQueue, - callback); - } else if (current) { - if (H264Converter::IsH264(aConfig)) { - nsRefPtr h - = new H264Converter(current, - *aConfig.GetAsVideoInfo(), - aLayersBackend, - aImageContainer, - aTaskQueue, - callback); - const nsresult rv = h->GetLastError(); - if (NS_SUCCEEDED(rv) || rv == NS_ERROR_NOT_INITIALIZED) { - // The H264Converter either successfully created the wrapped decoder, - // or there wasn't enough AVCC data to do so. Otherwise, there was some - // problem, for example WMF DLLs were missing. - m = h.forget(); - } - } else { - m = current->CreateVideoDecoder(*aConfig.GetAsVideoInfo(), - aLayersBackend, - aImageContainer, - aTaskQueue, - callback); + if (H264Converter::IsH264(aConfig)) { + nsRefPtr h + = new H264Converter(current, + *aConfig.GetAsVideoInfo(), + aLayersBackend, + aImageContainer, + aTaskQueue, + callback); + const nsresult rv = h->GetLastError(); + if (NS_SUCCEEDED(rv) || rv == NS_ERROR_NOT_INITIALIZED) { + // The H264Converter either successfully created the wrapped decoder, + // or there wasn't enough AVCC data to do so. Otherwise, there was some + // problem, for example WMF DLLs were missing. + m = h.forget(); } + } else { + m = current->CreateVideoDecoder(*aConfig.GetAsVideoInfo(), + aLayersBackend, + aImageContainer, + aTaskQueue, + callback); } if (callbackWrapper && m) { @@ -186,10 +170,7 @@ bool PDMFactory::SupportsMimeType(const nsACString& aMimeType) { nsRefPtr current = GetDecoder(aMimeType); - return current || - VPXDecoder::IsVPX(aMimeType) || - OpusDataDecoder::IsOpus(aMimeType) || - VorbisDataDecoder::IsVorbis(aMimeType); + return !!current; } void @@ -231,6 +212,10 @@ PDMFactory::CreatePDMs() StartupPDM(m); } #endif + + m = new AgnosticDecoderModule(); + StartupPDM(m); + if (sUseBlankDecoder) { m = CreateBlankDecoderModule(); StartupPDM(m); diff --git a/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp b/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp new file mode 100644 index 000000000000..c877e80f392f --- /dev/null +++ b/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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 "AgnosticDecoderModule.h" +#include "OpusDecoder.h" +#include "VorbisDecoder.h" +#include "VPXDecoder.h" + +namespace mozilla { + +bool +AgnosticDecoderModule::SupportsMimeType(const nsACString& aMimeType) +{ + return VPXDecoder::IsVPX(aMimeType) || + OpusDataDecoder::IsOpus(aMimeType) || + VorbisDataDecoder::IsVorbis(aMimeType); +} + +already_AddRefed +AgnosticDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig, + layers::LayersBackend aLayersBackend, + layers::ImageContainer* aImageContainer, + FlushableTaskQueue* aVideoTaskQueue, + MediaDataDecoderCallback* aCallback) +{ + nsRefPtr m; + + if (VPXDecoder::IsVPX(aConfig.mMimeType)) { + m = new VPXDecoder(*aConfig.GetAsVideoInfo(), + aImageContainer, + aVideoTaskQueue, + aCallback); + } + + return m.forget(); +} + +already_AddRefed +AgnosticDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig, + FlushableTaskQueue* aAudioTaskQueue, + MediaDataDecoderCallback* aCallback) +{ + nsRefPtr m; + + if (VorbisDataDecoder::IsVorbis(aConfig.mMimeType)) { + m = new VorbisDataDecoder(*aConfig.GetAsAudioInfo(), + aAudioTaskQueue, + aCallback); + } else if (OpusDataDecoder::IsOpus(aConfig.mMimeType)) { + m = new OpusDataDecoder(*aConfig.GetAsAudioInfo(), + aAudioTaskQueue, + aCallback); + } + + return m.forget(); +} + +} // namespace mozilla diff --git a/dom/media/platforms/agnostic/AgnosticDecoderModule.h b/dom/media/platforms/agnostic/AgnosticDecoderModule.h new file mode 100644 index 000000000000..97cc23e799b4 --- /dev/null +++ b/dom/media/platforms/agnostic/AgnosticDecoderModule.h @@ -0,0 +1,39 @@ +#if !defined(AgnosticDecoderModule_h_) +#define AgnosticDecoderModule_h_ + +#include "PlatformDecoderModule.h" + +namespace mozilla { + +class AgnosticDecoderModule : public PlatformDecoderModule { +public: + AgnosticDecoderModule() = default; + virtual ~AgnosticDecoderModule() = default; + + bool SupportsMimeType(const nsACString& aMimeType) override; + + ConversionRequired + DecoderNeedsConversion(const TrackInfo& aConfig) const override + { + return ConversionRequired::kNeedNone; + } + +protected: + // Decode thread. + already_AddRefed + CreateVideoDecoder(const VideoInfo& aConfig, + layers::LayersBackend aLayersBackend, + layers::ImageContainer* aImageContainer, + FlushableTaskQueue* aVideoTaskQueue, + MediaDataDecoderCallback* aCallback) override; + + // Decode thread. + already_AddRefed + CreateAudioDecoder(const AudioInfo& aConfig, + FlushableTaskQueue* aAudioTaskQueue, + MediaDataDecoderCallback* aCallback) override; +}; + +} // namespace mozilla + +#endif /* AgnosticDecoderModule_h_ */ diff --git a/dom/media/platforms/agnostic/BlankDecoderModule.cpp b/dom/media/platforms/agnostic/BlankDecoderModule.cpp index f176055f59dc..5b6e788f2964 100644 --- a/dom/media/platforms/agnostic/BlankDecoderModule.cpp +++ b/dom/media/platforms/agnostic/BlankDecoderModule.cpp @@ -259,27 +259,10 @@ public: }; -class AgnosticDecoderModule : public BlankDecoderModule { -public: - - bool SupportsMimeType(const nsACString& aMimeType) override - { - // This module does not support any decoders itself, - // agnostic decoders are created in PlatformDecoderModule::CreateDecoder - return false; - } -}; - already_AddRefed CreateBlankDecoderModule() { nsRefPtr pdm = new BlankDecoderModule(); return pdm.forget(); } -already_AddRefed CreateAgnosticDecoderModule() -{ - nsRefPtr adm = new AgnosticDecoderModule(); - return adm.forget(); -} - } // namespace mozilla diff --git a/dom/media/platforms/moz.build b/dom/media/platforms/moz.build index ae84d1f0144c..8a217ce267c1 100644 --- a/dom/media/platforms/moz.build +++ b/dom/media/platforms/moz.build @@ -5,6 +5,7 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. EXPORTS += [ + 'agnostic/AgnosticDecoderModule.h', 'agnostic/OpusDecoder.h', 'agnostic/VorbisDecoder.h', 'agnostic/VPXDecoder.h', @@ -14,6 +15,7 @@ EXPORTS += [ ] UNIFIED_SOURCES += [ + 'agnostic/AgnosticDecoderModule.cpp', 'agnostic/BlankDecoderModule.cpp', 'agnostic/OpusDecoder.cpp', 'agnostic/VorbisDecoder.cpp', From 046f9f13a98b7bbdcf0b8d43d0acacc3748ae9a2 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Tue, 6 Oct 2015 10:17:12 +1100 Subject: [PATCH 138/228] Bug 1206977: P5. Update PlatformDecoderModule documentation. r=cpearce Mostly removes no longer relevant doc. --- dom/media/platforms/PlatformDecoderModule.h | 39 +++++++++------------ 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/dom/media/platforms/PlatformDecoderModule.h b/dom/media/platforms/PlatformDecoderModule.h index e8d4426354d1..9c041e7a1171 100644 --- a/dom/media/platforms/PlatformDecoderModule.h +++ b/dom/media/platforms/PlatformDecoderModule.h @@ -30,24 +30,20 @@ class MediaDataDecoderCallback; class FlushableTaskQueue; class CDMProxy; -// The PlatformDecoderModule interface is used by the MP4Reader to abstract -// access to the H264 and Audio (AAC/MP3) decoders provided by various platforms. -// It may be extended to support other codecs in future. Each platform (Windows, -// MacOSX, Linux, B2G etc) must implement a PlatformDecoderModule to provide -// access to its decoders in order to get decompressed H.264/AAC from the -// MP4Reader. +// The PlatformDecoderModule interface is used by the MediaFormatReader to +// abstract access to decoders provided by various +// platforms. +// Each platform (Windows, MacOSX, Linux, B2G etc) must implement a +// PlatformDecoderModule to provide access to its decoders in order to get +// decompressed H.264/AAC from the MediaFormatReader. // -// Video decoding is asynchronous, and should be performed on the task queue +// Decoding is asynchronous, and should be performed on the task queue // provided if the underlying platform isn't already exposing an async API. // -// Platforms that don't have a corresponding PlatformDecoderModule won't be -// able to play the H.264/AAC data output by the MP4Reader. In practice this -// means that we won't have fragmented MP4 supported in Media Source -// Extensions. -// // A cross-platform decoder module that discards input and produces "blank" // output samples exists for testing, and is created when the pref // "media.fragmented-mp4.use-blank-decoder" is true. + class PlatformDecoderModule { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PlatformDecoderModule) @@ -59,8 +55,7 @@ public: // Factory method that creates the appropriate PlatformDecoderModule for // the platform we're running on. Caller is responsible for deleting this // instance. It's expected that there will be multiple - // PlatformDecoderModules alive at the same time. There is one - // PlatformDecoderModule created per MP4Reader. + // PlatformDecoderModules alive at the same time. // This is called on the decode task queue. static already_AddRefed Create(); @@ -90,10 +85,7 @@ public: MOZ_CRASH(); } - // An audio decoder module must support AAC by default. - // A video decoder must support H264 by default. - // If more codecs are to be supported, SupportsMimeType will have - // to be extended + // Indicates if the PlatformDecoderModule supports decoding of aMimeType. virtual bool SupportsMimeType(const nsACString& aMimeType); enum ConversionRequired { @@ -149,7 +141,8 @@ protected: }; // A callback used by MediaDataDecoder to return output/errors to the -// MP4Reader. Implementation is threadsafe, and can be called on any thread. +// MediaFormatReader. +// Implementation is threadsafe, and can be called on any thread. class MediaDataDecoderCallback { public: virtual ~MediaDataDecoderCallback() {} @@ -179,7 +172,7 @@ public: // // Unless otherwise noted, all functions are only called on the decode task // queue. An exception is the MediaDataDecoder in -// MP4Reader::IsVideoAccelerated() for which all calls (Init(), +// MediaFormatReader::IsVideoAccelerated() for which all calls (Init(), // IsHardwareAccelerated(), and Shutdown()) are from the main thread. // // Don't block inside these functions, unless it's explicitly noted that you @@ -207,7 +200,7 @@ public: // Initialize the decoder. The decoder should be ready to decode once // promise resolves. The decoder should do any initialization here, rather // than in its constructor or PlatformDecoderModule::Create*Decoder(), - // so that if the MP4Reader needs to shutdown during initialization, + // so that if the MediaFormatReader needs to shutdown during initialization, // it can call Shutdown() to cancel this operation. Any initialization // that requires blocking the calling thread in this function *must* // be done here so that it can be canceled by calling Shutdown()! @@ -222,7 +215,7 @@ public: // decoding resumes after the seek. // While the reader calls Flush(), it ignores all output sent to it; // it is safe (but pointless) to send output while Flush is called. - // The MP4Reader will not call Input() while it's calling Flush(). + // The MediaFormatReader will not call Input() while it's calling Flush(). virtual nsresult Flush() = 0; // Causes all complete samples in the pipeline that can be decoded to be @@ -230,7 +223,7 @@ public: // it drops the input samples. The decoder may be holding onto samples // that are required to decode samples that it expects to get in future. // This is called when the demuxer reaches end of stream. - // The MP4Reader will not call Input() while it's calling Drain(). + // The MediaFormatReader will not call Input() while it's calling Drain(). // This function is asynchronous. The MediaDataDecoder must call // MediaDataDecoderCallback::DrainComplete() once all remaining // samples have been output. From 7ad735710042faa4d0a2b0b111a81bcd5308cbd6 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Tue, 6 Oct 2015 10:23:26 +1100 Subject: [PATCH 139/228] Bug 1206977: P6. Make PlatformDecoderModule::SupportsMimeType pure virtual. r=cpearce --- dom/media/platforms/PlatformDecoderModule.cpp | 8 -------- dom/media/platforms/PlatformDecoderModule.h | 2 +- dom/media/platforms/agnostic/eme/EMEDecoderModule.h | 9 +++++++++ dom/media/platforms/agnostic/gmp/GMPDecoderModule.h | 8 ++++++++ dom/media/platforms/apple/AppleDecoderModule.cpp | 4 +++- 5 files changed, 21 insertions(+), 10 deletions(-) diff --git a/dom/media/platforms/PlatformDecoderModule.cpp b/dom/media/platforms/PlatformDecoderModule.cpp index fdb495744f8b..e47e30e4bac2 100644 --- a/dom/media/platforms/PlatformDecoderModule.cpp +++ b/dom/media/platforms/PlatformDecoderModule.cpp @@ -64,12 +64,4 @@ PlatformDecoderModule::Create() return m.forget(); } -bool -PlatformDecoderModule::SupportsMimeType(const nsACString& aMimeType) -{ - return aMimeType.EqualsLiteral("audio/mp4a-latm") || - aMimeType.EqualsLiteral("video/mp4") || - aMimeType.EqualsLiteral("video/avc"); -} - } // namespace mozilla diff --git a/dom/media/platforms/PlatformDecoderModule.h b/dom/media/platforms/PlatformDecoderModule.h index 9c041e7a1171..18b80827bcd5 100644 --- a/dom/media/platforms/PlatformDecoderModule.h +++ b/dom/media/platforms/PlatformDecoderModule.h @@ -86,7 +86,7 @@ public: } // Indicates if the PlatformDecoderModule supports decoding of aMimeType. - virtual bool SupportsMimeType(const nsACString& aMimeType); + virtual bool SupportsMimeType(const nsACString& aMimeType) = 0; enum ConversionRequired { kNeedNone, diff --git a/dom/media/platforms/agnostic/eme/EMEDecoderModule.h b/dom/media/platforms/agnostic/eme/EMEDecoderModule.h index 23740ecfeb1c..dd8c864fad5e 100644 --- a/dom/media/platforms/agnostic/eme/EMEDecoderModule.h +++ b/dom/media/platforms/agnostic/eme/EMEDecoderModule.h @@ -42,6 +42,15 @@ public: ConversionRequired DecoderNeedsConversion(const TrackInfo& aConfig) const override; + bool + SupportsMimeType(const nsACString& aMimeType) override + { + // TODO Properly. + return aMimeType.EqualsLiteral("audio/mp4a-latm") || + aMimeType.EqualsLiteral("video/mp4") || + aMimeType.EqualsLiteral("video/avc"); + } + private: nsRefPtr mProxy; // Will be null if CDM has decoding capability. diff --git a/dom/media/platforms/agnostic/gmp/GMPDecoderModule.h b/dom/media/platforms/agnostic/gmp/GMPDecoderModule.h index 990f8b804fcf..1a60997c96cc 100644 --- a/dom/media/platforms/agnostic/gmp/GMPDecoderModule.h +++ b/dom/media/platforms/agnostic/gmp/GMPDecoderModule.h @@ -33,6 +33,14 @@ public: ConversionRequired DecoderNeedsConversion(const TrackInfo& aConfig) const override; + + bool + SupportsMimeType(const nsACString& aMimeType) override + { + // TODO properly. + return aMimeType.EqualsLiteral("audio/mp4a-latm") || + aMimeType.EqualsLiteral("video/avc"); + } }; } // namespace mozilla diff --git a/dom/media/platforms/apple/AppleDecoderModule.cpp b/dom/media/platforms/apple/AppleDecoderModule.cpp index c9b82613e08d..8e0b1d482c48 100644 --- a/dom/media/platforms/apple/AppleDecoderModule.cpp +++ b/dom/media/platforms/apple/AppleDecoderModule.cpp @@ -110,7 +110,9 @@ bool AppleDecoderModule::SupportsMimeType(const nsACString& aMimeType) { return aMimeType.EqualsLiteral("audio/mpeg") || - PlatformDecoderModule::SupportsMimeType(aMimeType); + aMimeType.EqualsLiteral("audio/mp4a-latm") || + aMimeType.EqualsLiteral("video/mp4") || + aMimeType.EqualsLiteral("video/avc"); } PlatformDecoderModule::ConversionRequired From 6c9f5d095492d5854d41f026df12b7663d9ee928 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Tue, 6 Oct 2015 15:32:18 +1100 Subject: [PATCH 140/228] Bug 1206977: [webm] P7. Remove IntelWebMVideoDecoder. r=kinetik That code path is no longer used and handled directly in the MediaFormatReader. Also, partially revert commit ac6d0b0befb2 as it broke WebMReader. --- dom/media/webm/AudioDecoder.cpp | 12 +- dom/media/webm/IntelWebMVideoDecoder.cpp | 443 -------------------- dom/media/webm/IntelWebMVideoDecoder.h | 97 ----- dom/media/webm/SoftwareWebMVideoDecoder.cpp | 10 +- dom/media/webm/SoftwareWebMVideoDecoder.h | 4 +- dom/media/webm/WebMReader.cpp | 51 +-- dom/media/webm/WebMReader.h | 13 +- dom/media/webm/moz.build | 5 - 8 files changed, 16 insertions(+), 619 deletions(-) delete mode 100644 dom/media/webm/IntelWebMVideoDecoder.cpp delete mode 100644 dom/media/webm/IntelWebMVideoDecoder.h diff --git a/dom/media/webm/AudioDecoder.cpp b/dom/media/webm/AudioDecoder.cpp index 288aeadd752a..f23de9bad704 100644 --- a/dom/media/webm/AudioDecoder.cpp +++ b/dom/media/webm/AudioDecoder.cpp @@ -47,7 +47,7 @@ ogg_packet InitOggPacket(const unsigned char* aData, size_t aLength, class VorbisDecoder : public WebMAudioDecoder { public: - nsRefPtr Init() override; + nsresult Init() override; void Shutdown() override; nsresult ResetDecode() override; nsresult DecodeHeader(const unsigned char* aData, size_t aLength) override; @@ -94,14 +94,14 @@ VorbisDecoder::Shutdown() mReader = nullptr; } -nsRefPtr +nsresult VorbisDecoder::Init() { vorbis_info_init(&mVorbisInfo); vorbis_comment_init(&mVorbisComment); PodZero(&mVorbisDsp); PodZero(&mVorbisBlock); - return InitPromise::CreateAndResolve(TrackType::kAudioTrack, __func__); + return NS_OK; } nsresult @@ -229,7 +229,7 @@ VorbisDecoder::Decode(const unsigned char* aData, size_t aLength, class OpusDecoder : public WebMAudioDecoder { public: - nsRefPtr Init() override; + nsresult Init() override; void Shutdown() override; nsresult ResetDecode() override; nsresult DecodeHeader(const unsigned char* aData, size_t aLength) override; @@ -277,10 +277,10 @@ OpusDecoder::Shutdown() mReader = nullptr; } -nsRefPtr +nsresult OpusDecoder::Init() { - return InitPromise::CreateAndResolve(TrackType::kAudioTrack, __func__); + return NS_OK; } nsresult diff --git a/dom/media/webm/IntelWebMVideoDecoder.cpp b/dom/media/webm/IntelWebMVideoDecoder.cpp deleted file mode 100644 index e0bf886219a1..000000000000 --- a/dom/media/webm/IntelWebMVideoDecoder.cpp +++ /dev/null @@ -1,443 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 "IntelWebMVideoDecoder.h" - -#include "mozilla/TaskQueue.h" - -#include "gfx2DGlue.h" -#include "Layers.h" -#include "MediaResource.h" -#include "mozilla/dom/HTMLMediaElement.h" -#include "nsError.h" -#include "mozilla/SharedThreadPool.h" -#include "VorbisUtils.h" -#include "nestegg/nestegg.h" - -#define VPX_DONT_DEFINE_STDINT_TYPES -#include "vpx/vp8dx.h" -#include "vpx/vpx_decoder.h" - -#undef LOG -extern PRLogModuleInfo* GetPDMLog(); -#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__)) - -namespace mozilla { - -using layers::Image; -using layers::LayerManager; -using layers::LayersBackend; - -class VP8Sample : public MediaRawData -{ -public: - VP8Sample(int64_t aTimestamp, - int64_t aDuration, - int64_t aByteOffset, - uint8_t* aData, - size_t aSize, - bool aSyncPoint) - : MediaRawData(aData, aSize) - { - mTimecode = -1; - mTime = aTimestamp; - mDuration = aDuration; - mOffset = aByteOffset; - mKeyframe = aSyncPoint; - } -}; - -IntelWebMVideoDecoder::IntelWebMVideoDecoder(WebMReader* aReader) - : WebMVideoDecoder() - , mReader(aReader) - , mMonitor("IntelWebMVideoDecoder") - , mNumSamplesInput(0) - , mNumSamplesOutput(0) - , mDecodeAhead(2) - , mInputExhausted(false) - , mDrainComplete(false) - , mError(false) - , mEOS(false) - , mIsFlushing(false) -{ - MOZ_COUNT_CTOR(IntelWebMVideoDecoder); -} - -IntelWebMVideoDecoder::~IntelWebMVideoDecoder() -{ - MOZ_COUNT_DTOR(IntelWebMVideoDecoder); - Shutdown(); -} - -void -IntelWebMVideoDecoder::Shutdown() -{ - if (mMediaDataDecoder) { - Flush(); - mMediaDataDecoder->Shutdown(); - mMediaDataDecoder = nullptr; - } - - mTaskQueue = nullptr; - - mQueuedVideoSample = nullptr; - mReader = nullptr; -} - -/* static */ -WebMVideoDecoder* -IntelWebMVideoDecoder::Create(WebMReader* aReader) -{ - nsAutoPtr decoder(new IntelWebMVideoDecoder(aReader)); - - decoder->mTaskQueue = aReader->GetVideoTaskQueue(); - NS_ENSURE_TRUE(decoder->mTaskQueue, nullptr); - - return decoder.forget(); -} - -bool -IntelWebMVideoDecoder::IsSupportedVideoMimeType(const nsACString& aMimeType) -{ - return (aMimeType.EqualsLiteral("video/webm; codecs=vp8") || - aMimeType.EqualsLiteral("video/webm; codecs=vp9")) && - mPlatform->SupportsMimeType(aMimeType); -} - -nsRefPtr -IntelWebMVideoDecoder::Init(unsigned int aWidth, unsigned int aHeight) -{ - mPlatform = PlatformDecoderModule::Create(); - if (!mPlatform) { - return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__); - } - - mDecoderConfig = new VideoInfo(); - mDecoderConfig->mDuration = 0; - mDecoderConfig->mDisplay.width = aWidth; - mDecoderConfig->mDisplay.height = aHeight; - - switch (mReader->GetVideoCodec()) { - case NESTEGG_CODEC_VP8: - mDecoderConfig->mMimeType = "video/webm; codecs=vp8"; - break; - case NESTEGG_CODEC_VP9: - mDecoderConfig->mMimeType = "video/webm; codecs=vp9"; - break; - default: - return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__); - } - - const VideoInfo& video = *mDecoderConfig; - if (!IsSupportedVideoMimeType(video.mMimeType)) { - return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__); - } - mMediaDataDecoder = - mPlatform->CreateDecoder(video, - mTaskQueue, - this, - mReader->GetLayersBackendType(), - mReader->GetDecoder()->GetImageContainer()); - if (!mMediaDataDecoder) { - return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__); - } - - return mMediaDataDecoder->Init(); -} - -bool -IntelWebMVideoDecoder::Demux(nsRefPtr& aSample, bool* aEOS) -{ - nsRefPtr holder(mReader->NextPacket(WebMReader::VIDEO)); - if (!holder) { - return false; - } - - nestegg_packet* packet = holder->Packet(); - unsigned int track = 0; - int r = nestegg_packet_track(packet, &track); - if (r == -1) { - return false; - } - - unsigned int count = 0; - r = nestegg_packet_count(packet, &count); - if (r == -1) { - return false; - } - - if (count > 1) { - NS_WARNING("Packet contains more than one video frame"); - return false; - } - - int64_t tstamp = holder->Timestamp(); - - // The end time of this frame is the start time of the next frame. Fetch - // the timestamp of the next packet for this track. If we've reached the - // end of the resource, use the file's duration as the end time of this - // video frame. - int64_t next_tstamp = 0; - nsRefPtr next_holder(mReader->NextPacket(WebMReader::VIDEO)); - if (next_holder) { - next_tstamp = holder->Timestamp(); - mReader->PushVideoPacket(next_holder); - } else { - next_tstamp = tstamp; - next_tstamp += tstamp - mReader->GetLastVideoFrameTime(); - } - mReader->SetLastVideoFrameTime(tstamp); - - unsigned char* data; - size_t length; - r = nestegg_packet_data(packet, 0, &data, &length); - if (r == -1) { - return false; - } - - vpx_codec_stream_info_t si; - PodZero(&si); - si.sz = sizeof(si); - if (mReader->GetVideoCodec() == NESTEGG_CODEC_VP8) { - vpx_codec_peek_stream_info(vpx_codec_vp8_dx(), data, length, &si); - } else if (mReader->GetVideoCodec() == NESTEGG_CODEC_VP9) { - vpx_codec_peek_stream_info(vpx_codec_vp9_dx(), data, length, &si); - } - - MOZ_ASSERT(mPlatform && mMediaDataDecoder); - - aSample = new VP8Sample(tstamp, - next_tstamp - tstamp, - 0, - data, - length, - si.is_kf); - if (!aSample->Data()) { - return false; - } - - return true; -} - -bool -IntelWebMVideoDecoder::Decode() -{ - MOZ_ASSERT(mMediaDataDecoder); - - mMonitor.Lock(); - uint64_t prevNumFramesOutput = mNumSamplesOutput; - while (prevNumFramesOutput == mNumSamplesOutput) { - mMonitor.AssertCurrentThreadOwns(); - if (mError) { - // Decode error! - mMonitor.Unlock(); - return false; - } - while (prevNumFramesOutput == mNumSamplesOutput && - (mInputExhausted || - (mNumSamplesInput - mNumSamplesOutput) < mDecodeAhead) && - !mEOS) { - mMonitor.AssertCurrentThreadOwns(); - mMonitor.Unlock(); - nsRefPtr compressed(PopSample()); - if (!compressed) { - // EOS, or error. Let the state machine know there are no more - // frames coming. - LOG("Draining Video"); - mMonitor.Lock(); - MOZ_ASSERT(!mEOS); - mEOS = true; - MOZ_ASSERT(!mDrainComplete); - mDrainComplete = false; - mMonitor.Unlock(); - mMediaDataDecoder->Drain(); - } else { -#ifdef LOG_SAMPLE_DECODE - LOG("PopSample %s time=%lld dur=%lld", TrackTypeToStr(aTrack), - compressed->mTime, compressed->mDuration); -#endif - mMonitor.Lock(); - mDrainComplete = false; - mInputExhausted = false; - mNumSamplesInput++; - mMonitor.Unlock(); - if (NS_FAILED(mMediaDataDecoder->Input(compressed))) { - return false; - } - } - mMonitor.Lock(); - } - mMonitor.AssertCurrentThreadOwns(); - while (!mError && - prevNumFramesOutput == mNumSamplesOutput && - (!mInputExhausted || mEOS) && - !mDrainComplete) { - mMonitor.Wait(); - } - if (mError || - (mEOS && mDrainComplete)) { - break; - } - - } - mMonitor.AssertCurrentThreadOwns(); - bool rv = !(mEOS || mError); - mMonitor.Unlock(); - return rv; -} - -bool -IntelWebMVideoDecoder::SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint32_t& aParsed) -{ - MOZ_ASSERT(mReader->GetDecoder()); - - Flush(); - - // Loop until we reach the next keyframe after the threshold. - while (true) { - nsRefPtr compressed(PopSample()); - if (!compressed) { - // EOS, or error. Let the state machine know. - return false; - } - aParsed++; - if (!compressed->mKeyframe || - compressed->mTime < aTimeThreshold) { - continue; - } - mQueuedVideoSample = compressed; - break; - } - - return true; -} - -bool -IntelWebMVideoDecoder::DecodeVideoFrame(bool& aKeyframeSkip, - int64_t aTimeThreshold) -{ - AbstractMediaDecoder::AutoNotifyDecoded a(mReader->GetDecoder()); - - MOZ_ASSERT(mPlatform && mReader->GetDecoder()); - - if (aKeyframeSkip) { - bool ok = SkipVideoDemuxToNextKeyFrame(aTimeThreshold, a.mDropped); - if (!ok) { - NS_WARNING("Failed to skip demux up to next keyframe"); - return false; - } - a.mParsed = a.mDropped; - aKeyframeSkip = false; - nsresult rv = mMediaDataDecoder->Flush(); - NS_ENSURE_SUCCESS(rv, false); - } - - MOZ_ASSERT(mReader->OnTaskQueue()); - bool rv = Decode(); - { - // Report the number of "decoded" frames as the difference in the - // mNumSamplesOutput field since the last time we were called. - MonitorAutoLock mon(mMonitor); - uint64_t delta = mNumSamplesOutput - mLastReportedNumDecodedFrames; - a.mDecoded = static_cast(delta); - mLastReportedNumDecodedFrames = mNumSamplesOutput; - } - return rv; -} - -already_AddRefed -IntelWebMVideoDecoder::PopSample() -{ - if (mQueuedVideoSample) { - return mQueuedVideoSample.forget(); - } - nsRefPtr sample; - while (mSampleQueue.empty()) { - bool eos = false; - bool ok = Demux(sample, &eos); - if (!ok || eos) { - MOZ_ASSERT(!sample); - return nullptr; - } - MOZ_ASSERT(sample); - mSampleQueue.push_back(sample.forget()); - } - - MOZ_ASSERT(!mSampleQueue.empty()); - sample = mSampleQueue.front().forget(); - mSampleQueue.pop_front(); - return sample.forget(); -} - -void -IntelWebMVideoDecoder::Output(MediaData* aSample) -{ -#ifdef LOG_SAMPLE_DECODE - LOG("Decoded video sample time=%lld dur=%lld", - aSample->mTime, aSample->mDuration); -#endif - - // Don't accept output while we're flushing. - MonitorAutoLock mon(mMonitor); - if (mIsFlushing) { - mon.NotifyAll(); - return; - } - - MOZ_ASSERT(aSample->mType == MediaData::VIDEO_DATA); - mReader->VideoQueue().Push(static_cast(aSample)); - - mNumSamplesOutput++; - mon.NotifyAll(); -} - -void -IntelWebMVideoDecoder::DrainComplete() -{ - MonitorAutoLock mon(mMonitor); - mDrainComplete = true; - mon.NotifyAll(); -} - -void -IntelWebMVideoDecoder::InputExhausted() -{ - MonitorAutoLock mon(mMonitor); - mInputExhausted = true; - mon.NotifyAll(); -} - -void -IntelWebMVideoDecoder::Error() -{ - MonitorAutoLock mon(mMonitor); - mError = true; - mon.NotifyAll(); -} - -nsresult -IntelWebMVideoDecoder::Flush() -{ - if (!mReader->GetDecoder()) { - return NS_ERROR_FAILURE; - } - // Purge the current decoder's state. - // Set a flag so that we ignore all output while we call - // MediaDataDecoder::Flush(). - { - MonitorAutoLock mon(mMonitor); - mIsFlushing = true; - mDrainComplete = false; - mEOS = false; - } - mMediaDataDecoder->Flush(); - { - MonitorAutoLock mon(mMonitor); - mIsFlushing = false; - } - return NS_OK; -} - -} // namespace mozilla diff --git a/dom/media/webm/IntelWebMVideoDecoder.h b/dom/media/webm/IntelWebMVideoDecoder.h deleted file mode 100644 index 4d8343c10dcf..000000000000 --- a/dom/media/webm/IntelWebMVideoDecoder.h +++ /dev/null @@ -1,97 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ -#if !defined(IntelWebMVideoDecoder_h_) -#define IntelWebMVideoDecoder_h_ - -#include - -#include "WebMReader.h" -#include "nsAutoPtr.h" -#include "PlatformDecoderModule.h" -#include "mozilla/Monitor.h" - -#include "MediaInfo.h" -#include "MediaData.h" - -class TaskQueue; - -namespace mozilla { - -class VP8Sample; - -typedef std::deque> VP8SampleQueue; - -class IntelWebMVideoDecoder : public WebMVideoDecoder, public MediaDataDecoderCallback -{ -public: - static WebMVideoDecoder* Create(WebMReader* aReader); - virtual nsRefPtr Init(unsigned int aWidth = 0, - unsigned int aHeight = 0) override; - virtual nsresult Flush() override; - virtual void Shutdown() override; - - virtual bool DecodeVideoFrame(bool &aKeyframeSkip, - int64_t aTimeThreshold) override; - - virtual void Output(MediaData* aSample) override; - - virtual void DrainComplete() override; - - virtual void InputExhausted() override; - virtual void Error() override; - - virtual bool OnReaderTaskQueue() override - { - return mReader->OnTaskQueue(); - } - - IntelWebMVideoDecoder(WebMReader* aReader); - ~IntelWebMVideoDecoder(); - -private: - void InitLayersBackendType(); - - bool Decode(); - - bool Demux(nsRefPtr& aSample, bool* aEOS); - - bool SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint32_t& parsed); - - bool IsSupportedVideoMimeType(const nsACString& aMimeType); - - already_AddRefed PopSample(); - - nsRefPtr mReader; - nsRefPtr mPlatform; - nsRefPtr mMediaDataDecoder; - - // TaskQueue on which decoder can choose to decode. - // Only non-null up until the decoder is created. - nsRefPtr mTaskQueue; - - // Monitor that protects all non-threadsafe state; the primitives - // that follow. - Monitor mMonitor; - nsAutoPtr mDecoderConfig; - - VP8SampleQueue mSampleQueue; - nsRefPtr mQueuedVideoSample; - uint64_t mNumSamplesInput; - uint64_t mNumSamplesOutput; - uint64_t mLastReportedNumDecodedFrames; - uint32_t mDecodeAhead; - - // Whether this stream exists in the media. - bool mInputExhausted; - bool mDrainComplete; - bool mError; - bool mEOS; - bool mIsFlushing; -}; - -} // namespace mozilla - -#endif diff --git a/dom/media/webm/SoftwareWebMVideoDecoder.cpp b/dom/media/webm/SoftwareWebMVideoDecoder.cpp index 3e46e4ec6cc4..f7f6453b5b52 100644 --- a/dom/media/webm/SoftwareWebMVideoDecoder.cpp +++ b/dom/media/webm/SoftwareWebMVideoDecoder.cpp @@ -53,16 +53,10 @@ SoftwareWebMVideoDecoder::Create(WebMReader* aReader) return new SoftwareWebMVideoDecoder(aReader); } -nsRefPtr +nsresult SoftwareWebMVideoDecoder::Init(unsigned int aWidth, unsigned int aHeight) { - nsresult rv = InitDecoder(aWidth, aHeight); - - if (NS_SUCCEEDED(rv)) { - return InitPromise::CreateAndResolve(TrackType::kVideoTrack, __func__); - } - - return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__); + return InitDecoder(aWidth, aHeight); } nsresult diff --git a/dom/media/webm/SoftwareWebMVideoDecoder.h b/dom/media/webm/SoftwareWebMVideoDecoder.h index defa631638c0..2d3950691ab4 100644 --- a/dom/media/webm/SoftwareWebMVideoDecoder.h +++ b/dom/media/webm/SoftwareWebMVideoDecoder.h @@ -17,8 +17,8 @@ class SoftwareWebMVideoDecoder : public WebMVideoDecoder public: static WebMVideoDecoder* Create(WebMReader* aReader); - virtual nsRefPtr Init(unsigned int aWidth = 0, - unsigned int aHeight = 0) override; + virtual nsresult Init(unsigned int aWidth = 0, + unsigned int aHeight = 0) override; virtual bool DecodeVideoFrame(bool &aKeyframeSkip, int64_t aTimeThreshold) override; diff --git a/dom/media/webm/WebMReader.cpp b/dom/media/webm/WebMReader.cpp index 9fe76f1ee58a..a0e42b85d937 100644 --- a/dom/media/webm/WebMReader.cpp +++ b/dom/media/webm/WebMReader.cpp @@ -20,11 +20,6 @@ #include "vpx/vp8dx.h" #include "vpx/vpx_decoder.h" -// IntelWebMVideoDecoder uses the WMF backend, which is Windows Vista+ only. -#if defined(MOZ_PDM_VPX) -#include "IntelWebMVideoDecoder.h" -#endif - // Un-comment to enable logging of seek bisections. //#define SEEK_LOGGING @@ -125,10 +120,6 @@ static void webm_log(nestegg * context, va_end(args); } -#if defined(MOZ_PDM_VPX) -static bool sIsIntelDecoderEnabled = false; -#endif - WebMReader::WebMReader(AbstractMediaDecoder* aDecoder, TaskQueue* aBorrowedTaskQueue) : MediaDecoderReader(aDecoder, aBorrowedTaskQueue) , mContext(nullptr) @@ -149,10 +140,6 @@ WebMReader::WebMReader(AbstractMediaDecoder* aDecoder, TaskQueue* aBorrowedTaskQ if (!gNesteggLog) { gNesteggLog = PR_NewLogModule("Nestegg"); } - -#if defined(MOZ_PDM_VPX) - sIsIntelDecoderEnabled = Preferences::GetBool("media.webm.intel_decoder.enabled", false); -#endif } WebMReader::~WebMReader() @@ -168,12 +155,6 @@ WebMReader::~WebMReader() nsRefPtr WebMReader::Shutdown() { -#if defined(MOZ_PDM_VPX) - if (mVideoTaskQueue) { - mVideoTaskQueue->BeginShutdown(); - mVideoTaskQueue->AwaitShutdownAndIdle(); - } -#endif if (mAudioDecoder) { mAudioDecoder->Shutdown(); mAudioDecoder = nullptr; @@ -189,18 +170,6 @@ WebMReader::Shutdown() nsresult WebMReader::Init(MediaDecoderReader* aCloneDonor) { -#if defined(MOZ_PDM_VPX) - if (sIsIntelDecoderEnabled) { - PlatformDecoderModule::Init(); - - InitLayersBackendType(); - - mVideoTaskQueue = new FlushableTaskQueue( - SharedThreadPool::Get(NS_LITERAL_CSTRING("IntelVP8 Video Decode"))); - NS_ENSURE_TRUE(mVideoTaskQueue, NS_ERROR_FAILURE); - } -#endif - if (aCloneDonor) { mBufferedState = static_cast(aCloneDonor)->mBufferedState; } else { @@ -327,23 +296,13 @@ WebMReader::RetrieveWebMMetadata(MediaInfo* aInfo) mVideoCodec = nestegg_track_codec_id(mContext, track); -#if defined(MOZ_PDM_VPX) - if (sIsIntelDecoderEnabled) { - mVideoDecoder = IntelWebMVideoDecoder::Create(this); - } -#endif - - // If there's no decoder yet (e.g. HW decoder not available), use the software decoder. if (!mVideoDecoder) { mVideoDecoder = SoftwareWebMVideoDecoder::Create(this); } - if (mVideoDecoder) { - mInitPromises.AppendElement(mVideoDecoder->Init(params.display_width, - params.display_height)); - } - - if (!mVideoDecoder) { + if (!mVideoDecoder || + NS_FAILED(mVideoDecoder->Init(params.display_width, + params.display_height))) { Cleanup(); return NS_ERROR_FAILURE; } @@ -424,9 +383,7 @@ WebMReader::RetrieveWebMMetadata(MediaInfo* aInfo) return NS_ERROR_FAILURE; } - if (mAudioDecoder) { - mInitPromises.AppendElement(mAudioDecoder->Init()); - } else { + if (!mAudioDecoder || NS_FAILED(mAudioDecoder->Init())) { Cleanup(); return NS_ERROR_FAILURE; } diff --git a/dom/media/webm/WebMReader.h b/dom/media/webm/WebMReader.h index 6df8b4d67efb..8060654aaca2 100644 --- a/dom/media/webm/WebMReader.h +++ b/dom/media/webm/WebMReader.h @@ -11,7 +11,6 @@ #include "FlushableTaskQueue.h" #include "MediaDecoderReader.h" #include "MediaResource.h" -#include "PlatformDecoderModule.h" #include "nsAutoRef.h" #include "nestegg/nestegg.h" @@ -26,9 +25,7 @@ namespace mozilla { static const unsigned NS_PER_USEC = 1000; static const double NS_PER_S = 1e9; -typedef MediaDataDecoder::InitPromise InitPromise; typedef TrackInfo::TrackType TrackType; -typedef MediaDataDecoder::DecoderFailureReason DecoderFailureReason; class WebMBufferedState; class WebMPacketQueue; @@ -39,7 +36,7 @@ class WebMReader; class WebMVideoDecoder { public: - virtual nsRefPtr Init(unsigned int aWidth = 0, unsigned int aHeight = 0) = 0; + virtual nsresult Init(unsigned int aWidth = 0, unsigned int aHeight = 0) = 0; virtual nsresult Flush() { return NS_OK; } virtual void Shutdown() = 0; virtual bool DecodeVideoFrame(bool &aKeyframeSkip, @@ -52,7 +49,7 @@ public: class WebMAudioDecoder { public: - virtual nsRefPtr Init() = 0; + virtual nsresult Init() = 0; virtual void Shutdown() = 0; virtual nsresult ResetDecode() = 0; virtual nsresult DecodeHeader(const unsigned char* aData, size_t aLength) = 0; @@ -122,7 +119,6 @@ public: int64_t GetLastVideoFrameTime(); void SetLastVideoFrameTime(int64_t aFrameTime); layers::LayersBackend GetLayersBackendType() { return mLayersBackendType; } - FlushableTaskQueue* GetVideoTaskQueue() { return mVideoTaskQueue; } uint64_t GetCodecDelay() { return mCodecDelay; } protected: @@ -167,8 +163,6 @@ private: nsAutoPtr mAudioDecoder; nsAutoPtr mVideoDecoder; - nsTArray> mInitPromises; - // Queue of video and audio packets that have been read but not decoded. These // must only be accessed from the decode thread. WebMPacketQueue mVideoPackets; @@ -212,9 +206,6 @@ private: layers::LayersBackend mLayersBackendType; - // For hardware video decoding. - nsRefPtr mVideoTaskQueue; - // Booleans to indicate if we have audio and/or video data bool mHasVideo; bool mHasAudio; diff --git a/dom/media/webm/moz.build b/dom/media/webm/moz.build index cab25d63ee3a..8dd3e99bf24d 100644 --- a/dom/media/webm/moz.build +++ b/dom/media/webm/moz.build @@ -5,7 +5,6 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. EXPORTS += [ - 'IntelWebMVideoDecoder.h', 'NesteggPacketHolder.h', 'SoftwareWebMVideoDecoder.h', 'WebMBufferedParser.h', @@ -23,10 +22,6 @@ UNIFIED_SOURCES += [ 'WebMReader.cpp', ] -if CONFIG['MOZ_FMP4'] and CONFIG['MOZ_WMF']: - DEFINES['MOZ_PDM_VPX'] = True - UNIFIED_SOURCES += ['IntelWebMVideoDecoder.cpp'] - if CONFIG['MOZ_WEBM_ENCODER']: EXPORTS += ['WebMWriter.h'] UNIFIED_SOURCES += ['EbmlComposer.cpp', From 2da2bd26f97851b69e8dd599d6bf43638869005d Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Tue, 6 Oct 2015 19:56:29 +1100 Subject: [PATCH 141/228] Bug 1206977: P8. Have PDMFactory directly manage the EMEDecoderModule. r=cpearce --- dom/media/MediaFormatReader.cpp | 18 +++------- dom/media/MediaFormatReader.h | 4 +-- dom/media/platforms/PDMFactory.cpp | 33 +++++++++++++++++-- dom/media/platforms/PDMFactory.h | 12 +++++++ dom/media/platforms/PlatformDecoderModule.cpp | 30 ----------------- dom/media/platforms/PlatformDecoderModule.h | 10 ------ .../agnostic/eme/EMEDecoderModule.cpp | 2 +- .../platforms/agnostic/eme/EMEDecoderModule.h | 7 ++-- dom/media/platforms/moz.build | 1 + 9 files changed, 54 insertions(+), 63 deletions(-) diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp index 527c84141639..94961b925bf7 100644 --- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -169,7 +169,7 @@ nsresult MediaFormatReader::Init(MediaDecoderReader* aCloneDonor) { MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread."); - PlatformDecoderModule::Init(); + PDMFactory::Init(); InitLayersBackendType(); @@ -377,29 +377,19 @@ MediaFormatReader::EnsureDecodersCreated() MOZ_ASSERT(OnTaskQueue()); if (!mPlatform) { + mPlatform = new PDMFactory(); + NS_ENSURE_TRUE(mPlatform, false); if (IsEncrypted()) { #ifdef MOZ_EME - // We have encrypted audio or video. We'll need a CDM to decrypt and - // possibly decode this. Wait until we've received a CDM from the - // JavaScript player app. Note: we still go through the motions here - // even if EME is disabled, so that if script tries and fails to create - // a CDM, we can detect that and notify chrome and show some UI - // explaining that we failed due to EME being disabled. MOZ_ASSERT(mCDMProxy); - mPlatform = PlatformDecoderModule::CreateCDMWrapper(mCDMProxy); - NS_ENSURE_TRUE(mPlatform, false); + mPlatform->SetCDMProxy(mCDMProxy); #else // EME not supported. return false; #endif - } else { - mPlatform = PlatformDecoderModule::Create(); - NS_ENSURE_TRUE(mPlatform, false); } } - MOZ_ASSERT(mPlatform); - if (HasAudio() && !mAudio.mDecoder) { NS_ENSURE_TRUE(IsSupportedAudioMimeType(mInfo.mAudio.mMimeType), false); diff --git a/dom/media/MediaFormatReader.h b/dom/media/MediaFormatReader.h index 935648091b5c..03a4d462502f 100644 --- a/dom/media/MediaFormatReader.h +++ b/dom/media/MediaFormatReader.h @@ -13,7 +13,7 @@ #include "MediaDataDemuxer.h" #include "MediaDecoderReader.h" -#include "PlatformDecoderModule.h" +#include "PDMFactory.h" namespace mozilla { @@ -155,7 +155,7 @@ private: size_t SizeOfQueue(TrackType aTrack); nsRefPtr mDemuxer; - nsRefPtr mPlatform; + nsRefPtr mPlatform; class DecoderCallback : public MediaDataDecoderCallback { public: diff --git a/dom/media/platforms/PDMFactory.cpp b/dom/media/platforms/PDMFactory.cpp index 54006762716a..450f8f521222 100644 --- a/dom/media/platforms/PDMFactory.cpp +++ b/dom/media/platforms/PDMFactory.cpp @@ -34,6 +34,11 @@ #include "AgnosticDecoderModule.h" +#ifdef MOZ_EME +#include "EMEDecoderModule.h" +#include "mozilla/CDMProxy.h" +#endif + namespace mozilla { extern already_AddRefed CreateAgnosticDecoderModule(); @@ -109,7 +114,9 @@ PDMFactory::CreateDecoder(const TrackInfo& aConfig, layers::LayersBackend aLayersBackend, layers::ImageContainer* aImageContainer) { - nsRefPtr current = GetDecoder(aConfig.mMimeType); + nsRefPtr current = (mEMEPDM && aConfig.mCrypto.mValid) + ? mEMEPDM : GetDecoder(aConfig.mMimeType); + if (!current) { return nullptr; } @@ -117,8 +124,8 @@ PDMFactory::CreateDecoder(const TrackInfo& aConfig, if (aConfig.GetAsAudioInfo()) { m = current->CreateAudioDecoder(*aConfig.GetAsAudioInfo(), - aTaskQueue, - aCallback); + aTaskQueue, + aCallback); return m.forget(); } @@ -169,6 +176,9 @@ PDMFactory::CreateDecoder(const TrackInfo& aConfig, bool PDMFactory::SupportsMimeType(const nsACString& aMimeType) { + if (mEMEPDM) { + return mEMEPDM->SupportsMimeType(aMimeType); + } nsRefPtr current = GetDecoder(aMimeType); return !!current; } @@ -245,4 +255,21 @@ PDMFactory::GetDecoder(const nsACString& aMimeType) return pdm.forget(); } +#ifdef MOZ_EME +void +PDMFactory::SetCDMProxy(CDMProxy* aProxy) +{ + bool cdmDecodesAudio; + bool cdmDecodesVideo; + { + CDMCaps::AutoLock caps(aProxy->Capabilites()); + cdmDecodesAudio = caps.CanDecryptAndDecodeAudio(); + cdmDecodesVideo = caps.CanDecryptAndDecodeVideo(); + } + + nsRefPtr m = new PDMFactory(); + mEMEPDM = new EMEDecoderModule(aProxy, m, cdmDecodesAudio, cdmDecodesVideo); +} +#endif + } // namespace mozilla diff --git a/dom/media/platforms/PDMFactory.h b/dom/media/platforms/PDMFactory.h index 4f88f215ea4f..b6c8870dae8d 100644 --- a/dom/media/platforms/PDMFactory.h +++ b/dom/media/platforms/PDMFactory.h @@ -9,6 +9,8 @@ #include "PlatformDecoderModule.h" +class CDMProxy; + namespace mozilla { class PDMFactory : public PlatformDecoderModule { @@ -29,6 +31,15 @@ public: bool SupportsMimeType(const nsACString& aMimeType) override; +#ifdef MOZ_EME + // Creates a PlatformDecoderModule that uses a CDMProxy to decrypt or + // decrypt-and-decode EME encrypted content. If the CDM only decrypts and + // does not decode, we create a PDM and use that to create MediaDataDecoders + // that we use on on aTaskQueue to decode the decrypted stream. + // This is called on the decode task queue. + void SetCDMProxy(CDMProxy* aProxy); +#endif + ConversionRequired DecoderNeedsConversion(const TrackInfo& aConfig) const override { @@ -77,6 +88,7 @@ private: static bool sDontDelayInputExhausted; nsTArray> mCurrentPDMs; + nsRefPtr mEMEPDM; }; } // namespace mozilla diff --git a/dom/media/platforms/PlatformDecoderModule.cpp b/dom/media/platforms/PlatformDecoderModule.cpp index e47e30e4bac2..9f10a9402886 100644 --- a/dom/media/platforms/PlatformDecoderModule.cpp +++ b/dom/media/platforms/PlatformDecoderModule.cpp @@ -6,10 +6,6 @@ #include "PlatformDecoderModule.h" #include "PDMFactory.h" -#ifdef MOZ_EME -#include "EMEDecoderModule.h" -#include "mozilla/CDMProxy.h" -#endif PRLogModuleInfo* GetPDMLog() { static PRLogModuleInfo* log = nullptr; @@ -29,32 +25,6 @@ PlatformDecoderModule::Init() PDMFactory::Init(); } -#ifdef MOZ_EME -/* static */ -already_AddRefed -PlatformDecoderModule::CreateCDMWrapper(CDMProxy* aProxy) -{ - bool cdmDecodesAudio; - bool cdmDecodesVideo; - { - CDMCaps::AutoLock caps(aProxy->Capabilites()); - cdmDecodesAudio = caps.CanDecryptAndDecodeAudio(); - cdmDecodesVideo = caps.CanDecryptAndDecodeVideo(); - } - - // We always create a default PDM in order to decode - // non-encrypted tracks. - nsRefPtr pdm = Create(); - if (!pdm) { - return nullptr; - } - - nsRefPtr emepdm( - new EMEDecoderModule(aProxy, pdm, cdmDecodesAudio, cdmDecodesVideo)); - return emepdm.forget(); -} -#endif - /* static */ already_AddRefed PlatformDecoderModule::Create() diff --git a/dom/media/platforms/PlatformDecoderModule.h b/dom/media/platforms/PlatformDecoderModule.h index 18b80827bcd5..20dfaa86f537 100644 --- a/dom/media/platforms/PlatformDecoderModule.h +++ b/dom/media/platforms/PlatformDecoderModule.h @@ -63,16 +63,6 @@ public: // This is called on the decode task queue. virtual nsresult Startup() { return NS_OK; }; -#ifdef MOZ_EME - // Creates a PlatformDecoderModule that uses a CDMProxy to decrypt or - // decrypt-and-decode EME encrypted content. If the CDM only decrypts and - // does not decode, we create a PDM and use that to create MediaDataDecoders - // that we use on on aTaskQueue to decode the decrypted stream. - // This is called on the decode task queue. - static already_AddRefed - CreateCDMWrapper(CDMProxy* aProxy); -#endif - // Creates a decoder. // See CreateVideoDecoder and CreateAudioDecoder for implementation details. virtual already_AddRefed diff --git a/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp b/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp index a2fd57796f0b..46bccab7e483 100644 --- a/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp +++ b/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp @@ -191,7 +191,7 @@ EMEMediaDataDecoderProxy::Shutdown() } EMEDecoderModule::EMEDecoderModule(CDMProxy* aProxy, - PlatformDecoderModule* aPDM, + PDMFactory* aPDM, bool aCDMDecodesAudio, bool aCDMDecodesVideo) : mProxy(aProxy) diff --git a/dom/media/platforms/agnostic/eme/EMEDecoderModule.h b/dom/media/platforms/agnostic/eme/EMEDecoderModule.h index dd8c864fad5e..42e01f0c564a 100644 --- a/dom/media/platforms/agnostic/eme/EMEDecoderModule.h +++ b/dom/media/platforms/agnostic/eme/EMEDecoderModule.h @@ -8,6 +8,7 @@ #define EMEDecoderModule_h_ #include "PlatformDecoderModule.h" +#include "PDMFactory.h" #include "gmp-decryption.h" namespace mozilla { @@ -19,12 +20,13 @@ private: public: EMEDecoderModule(CDMProxy* aProxy, - PlatformDecoderModule* aPDM, + PDMFactory* aPDM, bool aCDMDecodesAudio, bool aCDMDecodesVideo); virtual ~EMEDecoderModule(); +protected: // Decode thread. already_AddRefed CreateVideoDecoder(const VideoInfo& aConfig, @@ -54,12 +56,11 @@ public: private: nsRefPtr mProxy; // Will be null if CDM has decoding capability. - nsRefPtr mPDM; + nsRefPtr mPDM; // We run the PDM on its own task queue. nsRefPtr mTaskQueue; bool mCDMDecodesAudio; bool mCDMDecodesVideo; - }; } // namespace mozilla diff --git a/dom/media/platforms/moz.build b/dom/media/platforms/moz.build index 8a217ce267c1..58f24494fd04 100644 --- a/dom/media/platforms/moz.build +++ b/dom/media/platforms/moz.build @@ -9,6 +9,7 @@ EXPORTS += [ 'agnostic/OpusDecoder.h', 'agnostic/VorbisDecoder.h', 'agnostic/VPXDecoder.h', + 'PDMFactory.h', 'PlatformDecoderModule.h', 'wrappers/FuzzingWrapper.h', 'wrappers/H264Converter.h' From 27b77f96da6bac84ae68b41c4743a21fc956f2e0 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Tue, 6 Oct 2015 20:10:31 +1100 Subject: [PATCH 142/228] Bug 1206977: P9. Ensure PDMs are only ever created through the PDMFactory. r=cpearce --- dom/media/MP3Decoder.cpp | 8 ++-- dom/media/fmp4/MP4Decoder.cpp | 23 +++++----- dom/media/platforms/PDMFactory.h | 45 +++++-------------- dom/media/platforms/PlatformDecoderModule.cpp | 22 --------- dom/media/platforms/PlatformDecoderModule.h | 23 ---------- 5 files changed, 26 insertions(+), 95 deletions(-) diff --git a/dom/media/MP3Decoder.cpp b/dom/media/MP3Decoder.cpp index c6415a26ce27..b4ae9e0b78ed 100644 --- a/dom/media/MP3Decoder.cpp +++ b/dom/media/MP3Decoder.cpp @@ -10,7 +10,7 @@ #include "MediaFormatReader.h" #include "MP3Demuxer.h" #include "mozilla/Preferences.h" -#include "PlatformDecoderModule.h" +#include "PDMFactory.h" namespace mozilla { @@ -32,10 +32,10 @@ MP3Decoder::CreateStateMachine() { static already_AddRefed CreateTestMP3Decoder(AudioInfo& aConfig) { - PlatformDecoderModule::Init(); + PDMFactory::Init(); - nsRefPtr platform = PlatformDecoderModule::Create(); - if (!platform || !platform->SupportsMimeType(aConfig.mMimeType)) { + nsRefPtr platform = new PDMFactory(); + if (!platform->SupportsMimeType(aConfig.mMimeType)) { return nullptr; } diff --git a/dom/media/fmp4/MP4Decoder.cpp b/dom/media/fmp4/MP4Decoder.cpp index bf15839327bf..517b75e7c6ae 100644 --- a/dom/media/fmp4/MP4Decoder.cpp +++ b/dom/media/fmp4/MP4Decoder.cpp @@ -31,6 +31,8 @@ #include "FFmpegRuntimeLinker.h" #endif +#include "PDMFactory.h" + namespace mozilla { #if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN) || defined(MOZ_APPLEMEDIA) || defined(MOZ_FFMPEG) @@ -149,11 +151,8 @@ MP4Decoder::CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs, } // Verify that we have a PDM that supports the whitelisted types. - PlatformDecoderModule::Init(); - nsRefPtr platform = PlatformDecoderModule::Create(); - if (!platform) { - return false; - } + PDMFactory::Init(); + nsRefPtr platform = new PDMFactory(); for (const nsCString& codecMime : codecMimes) { if (!platform->SupportsMimeType(codecMime)) { return false; @@ -184,7 +183,7 @@ IsFFmpegAvailable() #ifndef MOZ_FFMPEG return false; #else - PlatformDecoderModule::Init(); + PDMFactory::Init(); nsRefPtr m = FFmpegRuntimeLinker::CreateDecoderModule(); return !!m; #endif @@ -274,10 +273,10 @@ CreateTestH264Decoder(layers::LayersBackend aBackend, aConfig.mExtraData->AppendElements(sTestH264ExtraData, MOZ_ARRAY_LENGTH(sTestH264ExtraData)); - PlatformDecoderModule::Init(); + PDMFactory::Init(); - nsRefPtr platform = PlatformDecoderModule::Create(); - if (!platform || !platform->SupportsMimeType(NS_LITERAL_CSTRING("video/mp4"))) { + nsRefPtr platform = new PDMFactory(); + if (!platform->SupportsMimeType(NS_LITERAL_CSTRING("video/mp4"))) { return nullptr; } @@ -330,10 +329,10 @@ MP4Decoder::CanCreateH264Decoder() static already_AddRefed CreateTestAACDecoder(AudioInfo& aConfig) { - PlatformDecoderModule::Init(); + PDMFactory::Init(); - nsRefPtr platform = PlatformDecoderModule::Create(); - if (!platform || !platform->SupportsMimeType(NS_LITERAL_CSTRING("audio/mp4a-latm"))) { + nsRefPtr platform = new PDMFactory(); + if (!platform->SupportsMimeType(NS_LITERAL_CSTRING("audio/mp4a-latm"))) { return nullptr; } diff --git a/dom/media/platforms/PDMFactory.h b/dom/media/platforms/PDMFactory.h index b6c8870dae8d..7accf3776403 100644 --- a/dom/media/platforms/PDMFactory.h +++ b/dom/media/platforms/PDMFactory.h @@ -13,23 +13,29 @@ class CDMProxy; namespace mozilla { -class PDMFactory : public PlatformDecoderModule { +class PDMFactory final { public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PDMFactory) + PDMFactory(); - virtual ~PDMFactory(); // Call on the main thread to initialize the static state // needed by Create(). static void Init(); + // Factory method that creates the appropriate PlatformDecoderModule for + // the platform we're running on. Caller is responsible for deleting this + // instance. It's expected that there will be multiple + // PlatformDecoderModules alive at the same time. + // This is called on the decode task queue. already_AddRefed CreateDecoder(const TrackInfo& aConfig, FlushableTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback, layers::LayersBackend aLayersBackend = layers::LayersBackend::LAYERS_NONE, - layers::ImageContainer* aImageContainer = nullptr) override; + layers::ImageContainer* aImageContainer = nullptr); - bool SupportsMimeType(const nsACString& aMimeType) override; + bool SupportsMimeType(const nsACString& aMimeType); #ifdef MOZ_EME // Creates a PlatformDecoderModule that uses a CDMProxy to decrypt or @@ -40,37 +46,8 @@ public: void SetCDMProxy(CDMProxy* aProxy); #endif - ConversionRequired - DecoderNeedsConversion(const TrackInfo& aConfig) const override - { - MOZ_CRASH("Should never reach this function"); - return ConversionRequired::kNeedNone; - } - -protected: - // Decode thread. - already_AddRefed - CreateVideoDecoder(const VideoInfo& aConfig, - layers::LayersBackend aLayersBackend, - layers::ImageContainer* aImageContainer, - FlushableTaskQueue* aVideoTaskQueue, - MediaDataDecoderCallback* aCallback) override - { - MOZ_CRASH("Should never reach this function"); - return nullptr; - } - - // Decode thread. - already_AddRefed - CreateAudioDecoder(const AudioInfo& aConfig, - FlushableTaskQueue* aAudioTaskQueue, - MediaDataDecoderCallback* aCallback) override - { - MOZ_CRASH("Should never reach this function"); - return nullptr; - } - private: + virtual ~PDMFactory(); void CreatePDMs(); // Startup the provided PDM and add it to our list if successful. bool StartupPDM(PlatformDecoderModule* aPDM); diff --git a/dom/media/platforms/PlatformDecoderModule.cpp b/dom/media/platforms/PlatformDecoderModule.cpp index 9f10a9402886..bb02119700bc 100644 --- a/dom/media/platforms/PlatformDecoderModule.cpp +++ b/dom/media/platforms/PlatformDecoderModule.cpp @@ -5,7 +5,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "PlatformDecoderModule.h" -#include "PDMFactory.h" PRLogModuleInfo* GetPDMLog() { static PRLogModuleInfo* log = nullptr; @@ -14,24 +13,3 @@ PRLogModuleInfo* GetPDMLog() { } return log; } - -namespace mozilla { - -/* static */ -void -PlatformDecoderModule::Init() -{ - MOZ_ASSERT(NS_IsMainThread()); - PDMFactory::Init(); -} - -/* static */ -already_AddRefed -PlatformDecoderModule::Create() -{ - // Note: This (usually) runs on the decode thread. - nsRefPtr m = new PDMFactory; - return m.forget(); -} - -} // namespace mozilla diff --git a/dom/media/platforms/PlatformDecoderModule.h b/dom/media/platforms/PlatformDecoderModule.h index 20dfaa86f537..2191814dc4b2 100644 --- a/dom/media/platforms/PlatformDecoderModule.h +++ b/dom/media/platforms/PlatformDecoderModule.h @@ -48,33 +48,10 @@ class PlatformDecoderModule { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PlatformDecoderModule) - // Call on the main thread to initialize the static state - // needed by Create(). - static void Init(); - - // Factory method that creates the appropriate PlatformDecoderModule for - // the platform we're running on. Caller is responsible for deleting this - // instance. It's expected that there will be multiple - // PlatformDecoderModules alive at the same time. - // This is called on the decode task queue. - static already_AddRefed Create(); - // Perform any per-instance initialization. // This is called on the decode task queue. virtual nsresult Startup() { return NS_OK; }; - // Creates a decoder. - // See CreateVideoDecoder and CreateAudioDecoder for implementation details. - virtual already_AddRefed - CreateDecoder(const TrackInfo& aConfig, - FlushableTaskQueue* aTaskQueue, - MediaDataDecoderCallback* aCallback, - layers::LayersBackend aLayersBackend = layers::LayersBackend::LAYERS_NONE, - layers::ImageContainer* aImageContainer = nullptr) - { - MOZ_CRASH(); - } - // Indicates if the PlatformDecoderModule supports decoding of aMimeType. virtual bool SupportsMimeType(const nsACString& aMimeType) = 0; From 87d89f828c077d86de3569aecdc0071bb7ea0fac Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Tue, 6 Oct 2015 21:03:52 +1100 Subject: [PATCH 143/228] Bug 1206977: P10. Remove redundant code. r=cpearce The same checks are performed in the PDMFactory::SupportsMimeType --- dom/media/fmp4/MP4Decoder.cpp | 74 +---------------------------------- 1 file changed, 1 insertion(+), 73 deletions(-) diff --git a/dom/media/fmp4/MP4Decoder.cpp b/dom/media/fmp4/MP4Decoder.cpp index 517b75e7c6ae..4199cf9eff38 100644 --- a/dom/media/fmp4/MP4Decoder.cpp +++ b/dom/media/fmp4/MP4Decoder.cpp @@ -27,10 +27,6 @@ #endif #include "mozilla/layers/LayersTypes.h" -#ifdef MOZ_FFMPEG -#include "FFmpegRuntimeLinker.h" -#endif - #include "PDMFactory.h" namespace mozilla { @@ -177,79 +173,11 @@ MP4Decoder::CanHandleMediaType(const nsAString& aContentType) return CanHandleMediaType(NS_ConvertUTF16toUTF8(mimeType), codecs); } -static bool -IsFFmpegAvailable() -{ -#ifndef MOZ_FFMPEG - return false; -#else - PDMFactory::Init(); - nsRefPtr m = FFmpegRuntimeLinker::CreateDecoderModule(); - return !!m; -#endif -} - -static bool -IsAppleAvailable() -{ -#ifndef MOZ_APPLEMEDIA - // Not the right platform. - return false; -#else - return Preferences::GetBool("media.apple.mp4.enabled", false); -#endif -} - -static bool -IsAndroidAvailable() -{ -#ifndef MOZ_WIDGET_ANDROID - return false; -#else - // We need android.media.MediaCodec which exists in API level 16 and higher. - return AndroidBridge::Bridge() && (AndroidBridge::Bridge()->GetAPIVersion() >= 16); -#endif -} - -static bool -IsGonkMP4DecoderAvailable() -{ -#ifndef MOZ_GONK_MEDIACODEC - return false; -#else - return Preferences::GetBool("media.fragmented-mp4.gonk.enabled", false); -#endif -} - -static bool -IsGMPDecoderAvailable() -{ - return Preferences::GetBool("media.fragmented-mp4.gmp.enabled", false); -} - -static bool -HavePlatformMPEGDecoders() -{ - return Preferences::GetBool("media.fragmented-mp4.use-blank-decoder") || -#ifdef XP_WIN - // We have H.264/AAC platform decoders on Windows Vista and up. - IsVistaOrLater() || -#endif - IsAndroidAvailable() || - IsFFmpegAvailable() || - IsAppleAvailable() || - IsGonkMP4DecoderAvailable() || - IsGMPDecoderAvailable() || - // TODO: Other platforms... - false; -} - /* static */ bool MP4Decoder::IsEnabled() { - return Preferences::GetBool("media.fragmented-mp4.enabled") && - HavePlatformMPEGDecoders(); + return Preferences::GetBool("media.fragmented-mp4.enabled"); } static const uint8_t sTestH264ExtraData[] = { From b4365d5d77bf82f726d37113177e1a95ebbfc1aa Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Wed, 7 Oct 2015 10:37:38 +1100 Subject: [PATCH 144/228] Bug 1206977: P11. Don't rely on SupportsMimeType to determine if a track can be played. r=cpearce The PDMFactory will run more accurate checks based on the TrackInfo object and will fail to create a decoder if the type is unsupported. So use that instead --- dom/media/MP3Decoder.cpp | 7 ------- dom/media/MediaFormatReader.cpp | 18 ------------------ dom/media/MediaFormatReader.h | 2 -- dom/media/fmp4/MP4Decoder.cpp | 14 -------------- 4 files changed, 41 deletions(-) diff --git a/dom/media/MP3Decoder.cpp b/dom/media/MP3Decoder.cpp index b4ae9e0b78ed..f15dd1a23f50 100644 --- a/dom/media/MP3Decoder.cpp +++ b/dom/media/MP3Decoder.cpp @@ -35,15 +35,8 @@ CreateTestMP3Decoder(AudioInfo& aConfig) PDMFactory::Init(); nsRefPtr platform = new PDMFactory(); - if (!platform->SupportsMimeType(aConfig.mMimeType)) { - return nullptr; - } - nsRefPtr decoder( platform->CreateDecoder(aConfig, nullptr, nullptr)); - if (!decoder) { - return nullptr; - } return decoder.forget(); } diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp index 94961b925bf7..c1f79a7c14bd 100644 --- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -236,18 +236,6 @@ MediaFormatReader::IsWaitingOnCDMResource() { #endif } -bool -MediaFormatReader::IsSupportedAudioMimeType(const nsACString& aMimeType) -{ - return mPlatform && mPlatform->SupportsMimeType(aMimeType); -} - -bool -MediaFormatReader::IsSupportedVideoMimeType(const nsACString& aMimeType) -{ - return mPlatform && mPlatform->SupportsMimeType(aMimeType); -} - nsRefPtr MediaFormatReader::AsyncReadMetadata() { @@ -391,9 +379,6 @@ MediaFormatReader::EnsureDecodersCreated() } if (HasAudio() && !mAudio.mDecoder) { - NS_ENSURE_TRUE(IsSupportedAudioMimeType(mInfo.mAudio.mMimeType), - false); - mAudio.mDecoderInitialized = false; mAudio.mDecoder = mPlatform->CreateDecoder(mAudio.mInfo ? @@ -405,9 +390,6 @@ MediaFormatReader::EnsureDecodersCreated() } if (HasVideo() && !mVideo.mDecoder) { - NS_ENSURE_TRUE(IsSupportedVideoMimeType(mInfo.mVideo.mMimeType), - false); - mVideo.mDecoderInitialized = false; // Decoders use the layers backend to decide if they can use hardware decoding, // so specify LAYERS_NONE if we want to forcibly disable it. diff --git a/dom/media/MediaFormatReader.h b/dom/media/MediaFormatReader.h index 03a4d462502f..85951ab12df6 100644 --- a/dom/media/MediaFormatReader.h +++ b/dom/media/MediaFormatReader.h @@ -147,8 +147,6 @@ private: void Error(TrackType aTrack); void Flush(TrackType aTrack); void DrainComplete(TrackType aTrack); - bool IsSupportedAudioMimeType(const nsACString& aMimeType); - bool IsSupportedVideoMimeType(const nsACString& aMimeType); bool ShouldSkip(bool aSkipToNextKeyframe, media::TimeUnit aTimeThreshold); diff --git a/dom/media/fmp4/MP4Decoder.cpp b/dom/media/fmp4/MP4Decoder.cpp index 4199cf9eff38..97081b4a3825 100644 --- a/dom/media/fmp4/MP4Decoder.cpp +++ b/dom/media/fmp4/MP4Decoder.cpp @@ -204,15 +204,8 @@ CreateTestH264Decoder(layers::LayersBackend aBackend, PDMFactory::Init(); nsRefPtr platform = new PDMFactory(); - if (!platform->SupportsMimeType(NS_LITERAL_CSTRING("video/mp4"))) { - return nullptr; - } - nsRefPtr decoder( platform->CreateDecoder(aConfig, nullptr, nullptr, aBackend, nullptr)); - if (!decoder) { - return nullptr; - } return decoder.forget(); } @@ -260,15 +253,8 @@ CreateTestAACDecoder(AudioInfo& aConfig) PDMFactory::Init(); nsRefPtr platform = new PDMFactory(); - if (!platform->SupportsMimeType(NS_LITERAL_CSTRING("audio/mp4a-latm"))) { - return nullptr; - } - nsRefPtr decoder( platform->CreateDecoder(aConfig, nullptr, nullptr)); - if (!decoder) { - return nullptr; - } return decoder.forget(); } From 6f051abaa48314965c266675f2283e683f5396f1 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Wed, 7 Oct 2015 10:40:48 +1100 Subject: [PATCH 145/228] Bug 1206977: P12. Properly shutdown all created test decoders. r=cpearce --- dom/media/MP3Decoder.cpp | 1 + dom/media/fmp4/MP4Decoder.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/dom/media/MP3Decoder.cpp b/dom/media/MP3Decoder.cpp index f15dd1a23f50..588c26eecb4d 100644 --- a/dom/media/MP3Decoder.cpp +++ b/dom/media/MP3Decoder.cpp @@ -56,6 +56,7 @@ CanCreateMP3Decoder() config.mBitDepth = 16; nsRefPtr decoder(CreateTestMP3Decoder(config)); if (decoder) { + decoder->Shutdown(); result = true; } haveCachedResult = true; diff --git a/dom/media/fmp4/MP4Decoder.cpp b/dom/media/fmp4/MP4Decoder.cpp index 97081b4a3825..47ea102b02f8 100644 --- a/dom/media/fmp4/MP4Decoder.cpp +++ b/dom/media/fmp4/MP4Decoder.cpp @@ -220,6 +220,7 @@ MP4Decoder::IsVideoAccelerated(layers::LayersBackend aBackend, nsACString& aFail return false; } bool result = decoder->IsHardwareAccelerated(aFailureReason); + decoder->Shutdown(); return result; } @@ -293,6 +294,7 @@ MP4Decoder::CanCreateAACDecoder() MOZ_ARRAY_LENGTH(sTestAACExtraData)); nsRefPtr decoder(CreateTestAACDecoder(config)); if (decoder) { + decoder->Shutdown(); result = true; } haveCachedResult = true; From ac5814731cf2489b665858890e596d78efb11e94 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Wed, 7 Oct 2015 10:51:51 +1100 Subject: [PATCH 146/228] Bug 1206977: P13. Assert that data fed to EMEDecoderModule is encrypted. r=cpearce The PDMFactory ensures that the EMEDecoderModule is only used for encrypted data, we can simplify EMEDecoderModule and make strong assumptions --- .../platforms/agnostic/eme/EMEDecoderModule.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp b/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp index 46bccab7e483..bdf95e5632e9 100644 --- a/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp +++ b/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp @@ -230,7 +230,9 @@ EMEDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig, FlushableTaskQueue* aVideoTaskQueue, MediaDataDecoderCallback* aCallback) { - if (mCDMDecodesVideo && aConfig.mCrypto.mValid) { + MOZ_ASSERT(aConfig.mCrypto.mValid); + + if (mCDMDecodesVideo) { nsRefPtr wrapper = CreateDecoderWrapper(aCallback, mProxy, aVideoTaskQueue); wrapper->SetProxyTarget(new EMEVideoDecoder(mProxy, aConfig, @@ -252,10 +254,6 @@ EMEDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig, return nullptr; } - if (!aConfig.mCrypto.mValid) { - return decoder.forget(); - } - nsRefPtr emeDecoder(new EMEDecryptor(decoder, aCallback, mProxy, @@ -268,7 +266,9 @@ EMEDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig, FlushableTaskQueue* aAudioTaskQueue, MediaDataDecoderCallback* aCallback) { - if (mCDMDecodesAudio && aConfig.mCrypto.mValid) { + MOZ_ASSERT(aConfig.mCrypto.mValid); + + if (mCDMDecodesAudio) { nsRefPtr wrapper = CreateDecoderWrapper(aCallback, mProxy, aAudioTaskQueue); wrapper->SetProxyTarget(new EMEAudioDecoder(mProxy, aConfig, @@ -284,10 +284,6 @@ EMEDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig, return nullptr; } - if (!aConfig.mCrypto.mValid) { - return decoder.forget(); - } - nsRefPtr emeDecoder(new EMEDecryptor(decoder, aCallback, mProxy, From c3e24823e8b2515d6dfc30df1591f31754c2805d Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Wed, 7 Oct 2015 11:14:46 +1100 Subject: [PATCH 147/228] Bug 1206977: P14. Remove obsolete / redundant code. r=cpearce --- dom/media/MP3Decoder.cpp | 40 ++---------------- dom/media/fmp4/MP4Decoder.cpp | 80 ----------------------------------- dom/media/fmp4/MP4Decoder.h | 2 - 3 files changed, 4 insertions(+), 118 deletions(-) diff --git a/dom/media/MP3Decoder.cpp b/dom/media/MP3Decoder.cpp index 588c26eecb4d..c4bf6bab426e 100644 --- a/dom/media/MP3Decoder.cpp +++ b/dom/media/MP3Decoder.cpp @@ -29,44 +29,12 @@ MP3Decoder::CreateStateMachine() { return new MediaDecoderStateMachine(this, reader); } -static already_AddRefed -CreateTestMP3Decoder(AudioInfo& aConfig) -{ - PDMFactory::Init(); - - nsRefPtr platform = new PDMFactory(); - nsRefPtr decoder( - platform->CreateDecoder(aConfig, nullptr, nullptr)); - - return decoder.forget(); -} - -static bool -CanCreateMP3Decoder() -{ - static bool haveCachedResult = false; - static bool result = false; - if (haveCachedResult) { - return result; - } - AudioInfo config; - config.mMimeType = "audio/mpeg"; - config.mRate = 48000; - config.mChannels = 2; - config.mBitDepth = 16; - nsRefPtr decoder(CreateTestMP3Decoder(config)); - if (decoder) { - decoder->Shutdown(); - result = true; - } - haveCachedResult = true; - return result; -} - /* static */ bool MP3Decoder::IsEnabled() { - return CanCreateMP3Decoder(); + PDMFactory::Init(); + nsRefPtr platform = new PDMFactory(); + return platform->SupportsMimeType(NS_LITERAL_CSTRING("audio/mpeg")); } /* static */ @@ -74,7 +42,7 @@ bool MP3Decoder::CanHandleMediaType(const nsACString& aType, const nsAString& aCodecs) { if (aType.EqualsASCII("audio/mp3") || aType.EqualsASCII("audio/mpeg")) { - return CanCreateMP3Decoder() && + return IsEnabled() && (aCodecs.IsEmpty() || aCodecs.EqualsASCII("mp3")); } return false; diff --git a/dom/media/fmp4/MP4Decoder.cpp b/dom/media/fmp4/MP4Decoder.cpp index 47ea102b02f8..e92be5c3d630 100644 --- a/dom/media/fmp4/MP4Decoder.cpp +++ b/dom/media/fmp4/MP4Decoder.cpp @@ -224,84 +224,4 @@ MP4Decoder::IsVideoAccelerated(layers::LayersBackend aBackend, nsACString& aFail return result; } -/* static */ bool -MP4Decoder::CanCreateH264Decoder() -{ -#ifdef XP_WIN - static bool haveCachedResult = false; - static bool result = false; - if (haveCachedResult) { - return result; - } - VideoInfo config; - nsRefPtr decoder( - CreateTestH264Decoder(layers::LayersBackend::LAYERS_BASIC, config)); - if (decoder) { - decoder->Shutdown(); - result = true; - } - haveCachedResult = true; - return result; -#else - return IsEnabled(); -#endif -} - -#ifdef XP_WIN -static already_AddRefed -CreateTestAACDecoder(AudioInfo& aConfig) -{ - PDMFactory::Init(); - - nsRefPtr platform = new PDMFactory(); - nsRefPtr decoder( - platform->CreateDecoder(aConfig, nullptr, nullptr)); - - return decoder.forget(); -} - -// bipbop.mp4's extradata/config... -static const uint8_t sTestAACExtraData[] = { - 0x03, 0x80, 0x80, 0x80, 0x22, 0x00, 0x02, 0x00, 0x04, 0x80, - 0x80, 0x80, 0x14, 0x40, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x11, 0x51, 0x00, 0x00, 0x11, 0x51, 0x05, 0x80, 0x80, 0x80, - 0x02, 0x13, 0x90, 0x06, 0x80, 0x80, 0x80, 0x01, 0x02 -}; - -static const uint8_t sTestAACConfig[] = { 0x13, 0x90 }; - -#endif // XP_WIN - -/* static */ bool -MP4Decoder::CanCreateAACDecoder() -{ -#ifdef XP_WIN - static bool haveCachedResult = false; - static bool result = false; - if (haveCachedResult) { - return result; - } - AudioInfo config; - config.mMimeType = "audio/mp4a-latm"; - config.mRate = 22050; - config.mChannels = 2; - config.mBitDepth = 16; - config.mProfile = 2; - config.mExtendedProfile = 2; - config.mCodecSpecificConfig->AppendElements(sTestAACConfig, - MOZ_ARRAY_LENGTH(sTestAACConfig)); - config.mExtraData->AppendElements(sTestAACExtraData, - MOZ_ARRAY_LENGTH(sTestAACExtraData)); - nsRefPtr decoder(CreateTestAACDecoder(config)); - if (decoder) { - decoder->Shutdown(); - result = true; - } - haveCachedResult = true; - return result; -#else - return IsEnabled(); -#endif -} - } // namespace mozilla diff --git a/dom/media/fmp4/MP4Decoder.h b/dom/media/fmp4/MP4Decoder.h index aceec851aec9..f207838949eb 100644 --- a/dom/media/fmp4/MP4Decoder.h +++ b/dom/media/fmp4/MP4Decoder.h @@ -38,8 +38,6 @@ public: static bool IsEnabled(); static bool IsVideoAccelerated(layers::LayersBackend aBackend, nsACString& aReason); - static bool CanCreateAACDecoder(); - static bool CanCreateH264Decoder(); }; } // namespace mozilla From 61c233d099ecefa57fca9338d73cddffa59093a4 Mon Sep 17 00:00:00 2001 From: byron jones Date: Wed, 7 Oct 2015 11:16:07 +0530 Subject: [PATCH 148/228] Bug 1211780 - Don't try to use oldPasswordField if it's null. r=dolske --- toolkit/components/passwordmgr/LoginManagerContent.jsm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/toolkit/components/passwordmgr/LoginManagerContent.jsm b/toolkit/components/passwordmgr/LoginManagerContent.jsm index 9a08b8be19f8..d30354b3b6c0 100644 --- a/toolkit/components/passwordmgr/LoginManagerContent.jsm +++ b/toolkit/components/passwordmgr/LoginManagerContent.jsm @@ -714,7 +714,8 @@ var LoginManagerContent = { } log("Password field (new) id/name is: ", newPasswordField.id, " / ", newPasswordField.name); - log("Password field (old) id/name is: ", oldPasswordField.id, " / ", oldPasswordField.name); + if (oldPasswordField) + log("Password field (old) id/name is: ", oldPasswordField.id, " / ", oldPasswordField.name); return [usernameField, newPasswordField, oldPasswordField]; }, From bc8d5d3358ff27af1a1ef9dc8f29dfd5eb359690 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Pag=C3=A8s?= Date: Mon, 5 Oct 2015 22:08:35 +0200 Subject: [PATCH 149/228] Bug 1209772 - 'mozregression was installed. please re-run your command.' when running ./mach mozregression. r=ahal --- tools/mach_commands.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/mach_commands.py b/tools/mach_commands.py index 85a4ae7fc2b2..f97bedd1a095 100644 --- a/tools/mach_commands.py +++ b/tools/mach_commands.py @@ -397,7 +397,8 @@ def mozregression_create_parser(): # mozregression is not here at all, install it cmd.virtualenv_manager.install_pip_package('mozregression') print("mozregression was installed. please re-run your" - " command.") + " command. If you keep getting this message please " + " manually run: 'pip install -U mozregression'.") else: # check if there is a new release available release = mozregression.new_release_on_pypi() From 0eb9204d80d8deb9e69701f55958b2bf10f8623e Mon Sep 17 00:00:00 2001 From: James Kitchener Date: Wed, 7 Oct 2015 11:18:08 +0530 Subject: [PATCH 150/228] Bug 1101020 - Add the ability to fall back to not snapping, if snapping results in a zero area rect r=roc --- gfx/2d/PathHelpers.h | 26 +++++++++--- layout/base/nsLayoutUtils.cpp | 14 +++++++ layout/base/nsLayoutUtils.h | 11 ++++++ layout/mathml/nsMathMLFrame.cpp | 7 ++-- layout/reftests/mathml/radicalbar-1.html | 48 +++++++++++++++++++++++ layout/reftests/mathml/radicalbar-1a.html | 48 +++++++++++++++++++++++ layout/reftests/mathml/radicalbar-1b.html | 48 +++++++++++++++++++++++ layout/reftests/mathml/radicalbar-1c.html | 48 +++++++++++++++++++++++ layout/reftests/mathml/radicalbar-1d.html | 48 +++++++++++++++++++++++ layout/reftests/mathml/radicalbar-1e.html | 48 +++++++++++++++++++++++ layout/reftests/mathml/radicalbar-2.html | 47 ++++++++++++++++++++++ layout/reftests/mathml/radicalbar-2a.html | 47 ++++++++++++++++++++++ layout/reftests/mathml/radicalbar-2b.html | 47 ++++++++++++++++++++++ layout/reftests/mathml/radicalbar-2c.html | 47 ++++++++++++++++++++++ layout/reftests/mathml/radicalbar-2d.html | 47 ++++++++++++++++++++++ layout/reftests/mathml/radicalbar-2e.html | 47 ++++++++++++++++++++++ layout/reftests/mathml/radicalbar-3.html | 47 ++++++++++++++++++++++ layout/reftests/mathml/radicalbar-3a.html | 47 ++++++++++++++++++++++ layout/reftests/mathml/radicalbar-3b.html | 47 ++++++++++++++++++++++ layout/reftests/mathml/radicalbar-3c.html | 47 ++++++++++++++++++++++ layout/reftests/mathml/radicalbar-3d.html | 47 ++++++++++++++++++++++ layout/reftests/mathml/radicalbar-3e.html | 47 ++++++++++++++++++++++ layout/reftests/mathml/reftest.list | 18 +++++++++ 23 files changed, 920 insertions(+), 8 deletions(-) create mode 100644 layout/reftests/mathml/radicalbar-1.html create mode 100644 layout/reftests/mathml/radicalbar-1a.html create mode 100644 layout/reftests/mathml/radicalbar-1b.html create mode 100644 layout/reftests/mathml/radicalbar-1c.html create mode 100644 layout/reftests/mathml/radicalbar-1d.html create mode 100644 layout/reftests/mathml/radicalbar-1e.html create mode 100644 layout/reftests/mathml/radicalbar-2.html create mode 100644 layout/reftests/mathml/radicalbar-2a.html create mode 100644 layout/reftests/mathml/radicalbar-2b.html create mode 100644 layout/reftests/mathml/radicalbar-2c.html create mode 100644 layout/reftests/mathml/radicalbar-2d.html create mode 100644 layout/reftests/mathml/radicalbar-2e.html create mode 100644 layout/reftests/mathml/radicalbar-3.html create mode 100644 layout/reftests/mathml/radicalbar-3a.html create mode 100644 layout/reftests/mathml/radicalbar-3b.html create mode 100644 layout/reftests/mathml/radicalbar-3c.html create mode 100644 layout/reftests/mathml/radicalbar-3d.html create mode 100644 layout/reftests/mathml/radicalbar-3e.html diff --git a/gfx/2d/PathHelpers.h b/gfx/2d/PathHelpers.h index 4dbc0aac8fbe..7a4fac98975d 100644 --- a/gfx/2d/PathHelpers.h +++ b/gfx/2d/PathHelpers.h @@ -352,9 +352,14 @@ extern UserDataKey sDisablePixelSnapping; * boundaries.) If on the other hand you stroking the rect with an odd valued * stroke width then the edges of the stroke will be antialiased (assuming an * AntialiasMode that does antialiasing). + * + * Empty snaps are those which result in a rectangle of 0 area. If they are + * disallowed, an axis is left unsnapped if the rounding process results in a + * length of 0. */ inline bool UserToDevicePixelSnapped(Rect& aRect, const DrawTarget& aDrawTarget, - bool aAllowScaleOr90DegreeRotate = false) + bool aAllowScaleOr90DegreeRotate = false, + bool aAllowEmptySnaps = true) { if (aDrawTarget.GetUserData(&sDisablePixelSnapping)) { return false; @@ -383,8 +388,18 @@ inline bool UserToDevicePixelSnapped(Rect& aRect, const DrawTarget& aDrawTarget, // We actually only need to check one of p2 and p4, since an affine // transform maps parallelograms to parallelograms. if (p2 == Point(p1.x, p3.y) || p2 == Point(p3.x, p1.y)) { - p1.Round(); - p3.Round(); + Point p1r = p1; + Point p3r = p3; + p1r.Round(); + p3r.Round(); + if (aAllowEmptySnaps || p1r.x != p3r.x) { + p1.x = p1r.x; + p3.x = p3r.x; + } + if (aAllowEmptySnaps || p1r.y != p3r.y) { + p1.y = p1r.y; + p3.y = p3r.y; + } aRect.MoveTo(Point(std::min(p1.x, p3.x), std::min(p1.y, p3.y))); aRect.SizeTo(Size(std::max(p1.x, p3.x) - aRect.X(), @@ -400,10 +415,11 @@ inline bool UserToDevicePixelSnapped(Rect& aRect, const DrawTarget& aDrawTarget, * aRect is not transformed to device space. */ inline bool MaybeSnapToDevicePixels(Rect& aRect, const DrawTarget& aDrawTarget, - bool aAllowScaleOr90DegreeRotate = false) + bool aAllowScaleOr90DegreeRotate = false, + bool aAllowEmptySnaps = true) { if (UserToDevicePixelSnapped(aRect, aDrawTarget, - aAllowScaleOr90DegreeRotate)) { + aAllowScaleOr90DegreeRotate, aAllowEmptySnaps)) { // Since UserToDevicePixelSnapped returned true we know there is no // rotation/skew in 'mat', so we can just use TransformBounds() here. Matrix mat = aDrawTarget.GetTransform(); diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 0d6ccd8a8f48..8e33bd82ebae 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -8101,6 +8101,20 @@ Rect NSRectToSnappedRect(const nsRect& aRect, double aAppUnitsPerPixel, MaybeSnapToDevicePixels(rect, aSnapDT, true); return rect; } +// Similar to a snapped rect, except an axis is left unsnapped if the snapping +// process results in a length of 0. +Rect NSRectToNonEmptySnappedRect(const nsRect& aRect, double aAppUnitsPerPixel, + const gfx::DrawTarget& aSnapDT) +{ + // Note that by making aAppUnitsPerPixel a double we're doing floating-point + // division using a larger type and avoiding rounding error. + Rect rect(Float(aRect.x / aAppUnitsPerPixel), + Float(aRect.y / aAppUnitsPerPixel), + Float(aRect.width / aAppUnitsPerPixel), + Float(aRect.height / aAppUnitsPerPixel)); + MaybeSnapToDevicePixels(rect, aSnapDT, true, false); + return rect; +} void StrokeLineWithSnapping(const nsPoint& aP1, const nsPoint& aP2, int32_t aAppUnitsPerDevPixel, diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index d74022b5005b..f8c68f832e7f 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -2860,6 +2860,17 @@ gfx::Rect NSRectToRect(const nsRect& aRect, double aAppUnitsPerPixel); gfx::Rect NSRectToSnappedRect(const nsRect& aRect, double aAppUnitsPerPixel, const gfx::DrawTarget& aSnapDT); +/** +* Converts, where possible, an nsRect in app units to a Moz2D Rect in pixels +* (whether those are device pixels or CSS px depends on what the caller +* chooses to pass as aAppUnitsPerPixel). +* +* If snapping results in a rectangle with zero width or height, the affected +* coordinates are left unsnapped +*/ +gfx::Rect NSRectToNonEmptySnappedRect(const nsRect& aRect, double aAppUnitsPerPixel, + const gfx::DrawTarget& aSnapDT); + void StrokeLineWithSnapping(const nsPoint& aP1, const nsPoint& aP2, int32_t aAppUnitsPerDevPixel, gfx::DrawTarget& aDrawTarget, diff --git a/layout/mathml/nsMathMLFrame.cpp b/layout/mathml/nsMathMLFrame.cpp index db541ada40c4..66ad07d347ec 100644 --- a/layout/mathml/nsMathMLFrame.cpp +++ b/layout/mathml/nsMathMLFrame.cpp @@ -363,9 +363,10 @@ void nsDisplayMathMLBar::Paint(nsDisplayListBuilder* aBuilder, { // paint the bar with the current text color DrawTarget* drawTarget = aCtx->GetDrawTarget(); - Rect rect = NSRectToSnappedRect(mRect + ToReferenceFrame(), - mFrame->PresContext()->AppUnitsPerDevPixel(), - *drawTarget); + Rect rect = + NSRectToNonEmptySnappedRect(mRect + ToReferenceFrame(), + mFrame->PresContext()->AppUnitsPerDevPixel(), + *drawTarget); ColorPattern color(ToDeviceColor( mFrame->GetVisitedDependentColor(eCSSProperty_color))); drawTarget->FillRect(rect, color); diff --git a/layout/reftests/mathml/radicalbar-1.html b/layout/reftests/mathml/radicalbar-1.html new file mode 100644 index 000000000000..7ee38149dd20 --- /dev/null +++ b/layout/reftests/mathml/radicalbar-1.html @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + +
+ + + diff --git a/layout/reftests/mathml/radicalbar-1a.html b/layout/reftests/mathml/radicalbar-1a.html new file mode 100644 index 000000000000..3b43eb90922d --- /dev/null +++ b/layout/reftests/mathml/radicalbar-1a.html @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + +
+ + + diff --git a/layout/reftests/mathml/radicalbar-1b.html b/layout/reftests/mathml/radicalbar-1b.html new file mode 100644 index 000000000000..3d49caa38dde --- /dev/null +++ b/layout/reftests/mathml/radicalbar-1b.html @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + +
+ + + diff --git a/layout/reftests/mathml/radicalbar-1c.html b/layout/reftests/mathml/radicalbar-1c.html new file mode 100644 index 000000000000..3ebff2420370 --- /dev/null +++ b/layout/reftests/mathml/radicalbar-1c.html @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + +
+ + + diff --git a/layout/reftests/mathml/radicalbar-1d.html b/layout/reftests/mathml/radicalbar-1d.html new file mode 100644 index 000000000000..70c8ed936092 --- /dev/null +++ b/layout/reftests/mathml/radicalbar-1d.html @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + +
+ + + diff --git a/layout/reftests/mathml/radicalbar-1e.html b/layout/reftests/mathml/radicalbar-1e.html new file mode 100644 index 000000000000..560c8175cc0b --- /dev/null +++ b/layout/reftests/mathml/radicalbar-1e.html @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + +
+ + + diff --git a/layout/reftests/mathml/radicalbar-2.html b/layout/reftests/mathml/radicalbar-2.html new file mode 100644 index 000000000000..140d0e037ba2 --- /dev/null +++ b/layout/reftests/mathml/radicalbar-2.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + +
+ + diff --git a/layout/reftests/mathml/radicalbar-2a.html b/layout/reftests/mathml/radicalbar-2a.html new file mode 100644 index 000000000000..ff31625f0678 --- /dev/null +++ b/layout/reftests/mathml/radicalbar-2a.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + +
+ + diff --git a/layout/reftests/mathml/radicalbar-2b.html b/layout/reftests/mathml/radicalbar-2b.html new file mode 100644 index 000000000000..8d2736fc60b4 --- /dev/null +++ b/layout/reftests/mathml/radicalbar-2b.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + +
+ + diff --git a/layout/reftests/mathml/radicalbar-2c.html b/layout/reftests/mathml/radicalbar-2c.html new file mode 100644 index 000000000000..1e9f01777490 --- /dev/null +++ b/layout/reftests/mathml/radicalbar-2c.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + +
+ + diff --git a/layout/reftests/mathml/radicalbar-2d.html b/layout/reftests/mathml/radicalbar-2d.html new file mode 100644 index 000000000000..b92ed920f067 --- /dev/null +++ b/layout/reftests/mathml/radicalbar-2d.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + +
+ + diff --git a/layout/reftests/mathml/radicalbar-2e.html b/layout/reftests/mathml/radicalbar-2e.html new file mode 100644 index 000000000000..4685d0318fe6 --- /dev/null +++ b/layout/reftests/mathml/radicalbar-2e.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + +
+ + diff --git a/layout/reftests/mathml/radicalbar-3.html b/layout/reftests/mathml/radicalbar-3.html new file mode 100644 index 000000000000..929ff534da64 --- /dev/null +++ b/layout/reftests/mathml/radicalbar-3.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + +
+ + diff --git a/layout/reftests/mathml/radicalbar-3a.html b/layout/reftests/mathml/radicalbar-3a.html new file mode 100644 index 000000000000..5708e38a79a7 --- /dev/null +++ b/layout/reftests/mathml/radicalbar-3a.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + +
+ + diff --git a/layout/reftests/mathml/radicalbar-3b.html b/layout/reftests/mathml/radicalbar-3b.html new file mode 100644 index 000000000000..8343654acb35 --- /dev/null +++ b/layout/reftests/mathml/radicalbar-3b.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + +
+ + diff --git a/layout/reftests/mathml/radicalbar-3c.html b/layout/reftests/mathml/radicalbar-3c.html new file mode 100644 index 000000000000..c5f5e5a65eb5 --- /dev/null +++ b/layout/reftests/mathml/radicalbar-3c.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + +
+ + diff --git a/layout/reftests/mathml/radicalbar-3d.html b/layout/reftests/mathml/radicalbar-3d.html new file mode 100644 index 000000000000..99e7790fb04e --- /dev/null +++ b/layout/reftests/mathml/radicalbar-3d.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + +
+ + diff --git a/layout/reftests/mathml/radicalbar-3e.html b/layout/reftests/mathml/radicalbar-3e.html new file mode 100644 index 000000000000..bd361157f664 --- /dev/null +++ b/layout/reftests/mathml/radicalbar-3e.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + +
+ + diff --git a/layout/reftests/mathml/reftest.list b/layout/reftests/mathml/reftest.list index de7b5fb220e4..910e53ddb5df 100644 --- a/layout/reftests/mathml/reftest.list +++ b/layout/reftests/mathml/reftest.list @@ -366,3 +366,21 @@ fails-if(winWidget) == mfrac-D-2.html mfrac-D-2-ref.html test-pref(dom.webcomponents.enabled,true) == shadow-dom-1.html shadow-dom-1-ref.html pref(font.size.inflation.emPerLine,25) == font-inflation-1.html font-inflation-1-ref.html test-pref(font.minimum-size.x-math,40) == default-font.html default-font-ref.html +!= radicalbar-1.html about:blank +!= radicalbar-1a.html about:blank +!= radicalbar-1b.html about:blank +!= radicalbar-1c.html about:blank +!= radicalbar-1d.html about:blank +!= radicalbar-1e.html about:blank +!= radicalbar-2.html about:blank +!= radicalbar-2a.html about:blank +!= radicalbar-2b.html about:blank +!= radicalbar-2c.html about:blank +!= radicalbar-2d.html about:blank +!= radicalbar-2e.html about:blank +!= radicalbar-3.html about:blank +!= radicalbar-3a.html about:blank +!= radicalbar-3b.html about:blank +!= radicalbar-3c.html about:blank +!= radicalbar-3d.html about:blank +!= radicalbar-3e.html about:blank From 339a21eccf6406e52b5f7820ef8ea283c96f26f7 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Wed, 7 Oct 2015 12:00:52 +1100 Subject: [PATCH 151/228] Bug 1212164: Prevent use of demuxer before it is ready. r=cpearce --- dom/media/MediaFormatReader.cpp | 8 ++++++-- dom/media/MediaFormatReader.h | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp index c1f79a7c14bd..6b0af2bcdf2b 100644 --- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -63,9 +63,10 @@ MediaFormatReader::MediaFormatReader(AbstractMediaDecoder* aDecoder, MediaDataDemuxer* aDemuxer, TaskQueue* aBorrowedTaskQueue) : MediaDecoderReader(aDecoder, aBorrowedTaskQueue) - , mDemuxer(aDemuxer) , mAudio(this, MediaData::AUDIO_DATA, Preferences::GetUint("media.audio-decode-ahead", 2)) , mVideo(this, MediaData::VIDEO_DATA, Preferences::GetUint("media.video-decode-ahead", 2)) + , mDemuxer(aDemuxer) + , mDemuxerInitDone(false) , mLastReportedNumDecodedFrames(0) , mLayersBackendType(layers::LayersBackend::LAYERS_NONE) , mInitDone(false) @@ -272,6 +273,8 @@ MediaFormatReader::OnDemuxerInitDone(nsresult) MOZ_ASSERT(OnTaskQueue()); mDemuxerInitRequest.Complete(); + mDemuxerInitDone = true; + // To decode, we need valid video and a place to put it. bool videoActive = !!mDemuxer->GetNumberTracks(TrackInfo::kVideoTrack) && mDecoder->GetImageContainer(); @@ -1593,7 +1596,8 @@ MediaFormatReader::NotifyDemuxer(uint32_t aLength, int64_t aOffset) MOZ_ASSERT(OnTaskQueue()); LOGV("aLength=%u, aOffset=%lld", aLength, aOffset); - if (mShutdown || !mDemuxer) { + if (mShutdown || !mDemuxer || + (!mDemuxerInitDone && !mDemuxerInitRequest.Exists())) { return; } diff --git a/dom/media/MediaFormatReader.h b/dom/media/MediaFormatReader.h index 85951ab12df6..64f1d5c92112 100644 --- a/dom/media/MediaFormatReader.h +++ b/dom/media/MediaFormatReader.h @@ -152,7 +152,6 @@ private: size_t SizeOfQueue(TrackType aTrack); - nsRefPtr mDemuxer; nsRefPtr mPlatform; class DecoderCallback : public MediaDataDecoderCallback { @@ -355,6 +354,8 @@ private: void OnDecoderInitFailed(MediaDataDecoder::DecoderFailureReason aReason); // Demuxer objects. + nsRefPtr mDemuxer; + bool mDemuxerInitDone; void OnDemuxerInitDone(nsresult); void OnDemuxerInitFailed(DemuxerFailureReason aFailure); MozPromiseRequestHolder mDemuxerInitRequest; From d346e51c8ddcce400ee10d2121bfc843ade47b09 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Tue, 6 Oct 2015 18:24:03 +0200 Subject: [PATCH 152/228] Bug 1211956: Check result of EmptyShape::getInitialShape; r=h4writer --HG-- extra : rebase_source : c2ec5ca1e09c8c5919a51469218bf58c070a8c54 --- js/src/vm/Shape.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index 515ee20a4004..3c030d556fd7 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -627,6 +627,9 @@ js::ReshapeForAllocKind(JSContext* cx, Shape* shape, TaggedProto proto, RootedId id(cx); RootedShape newShape(cx, EmptyShape::getInitialShape(cx, shape->getObjectClass(), proto, nfixed, shape->getObjectFlags())); + if (!newShape) + return nullptr; + for (unsigned i = 0; i < ids.length(); i++) { id = ids[i]; From 8eeed2459b609247069ca45c7fdedea8ff38555c Mon Sep 17 00:00:00 2001 From: Tracy Walker Date: Tue, 6 Oct 2015 07:46:36 -0500 Subject: [PATCH 153/228] Bug 1100664: Make test case browser/base/content/test/general/browser_minimize.js more e10s friendly by using add_task() and support for querying active state added in bug 1199765. r=jimm --HG-- extra : rebase_source : 5a26b9382bc68b570feec964a0ec56c52ba75124 --- .../content/test/general/browser_minimize.js | 41 +++++-------------- 1 file changed, 11 insertions(+), 30 deletions(-) diff --git a/browser/base/content/test/general/browser_minimize.js b/browser/base/content/test/general/browser_minimize.js index 459f84b442b3..8a6c7a5938d7 100644 --- a/browser/base/content/test/general/browser_minimize.js +++ b/browser/base/content/test/general/browser_minimize.js @@ -1,37 +1,18 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ -function waitForActive() { - if (!gBrowser.docShell.isActive) { - executeSoon(waitForActive); - return; - } - is(gBrowser.docShell.isActive, true, "Docshell should be active again"); - finish(); -} -function waitForInactive() { - if (gBrowser.docShell.isActive) { - executeSoon(waitForInactive); - return; - } - is(gBrowser.docShell.isActive, false, "Docshell should be inactive"); - window.restore(); - waitForActive(); -} - -function test() { +add_task(function *() { registerCleanupFunction(function() { window.restore(); }); - - waitForExplicitFinish(); - is(gBrowser.docShell.isActive, true, "Docshell should be active"); + function waitForActive() { return gBrowser.selectedTab.linkedBrowser.docShellIsActive; } + function waitForInactive() { return !gBrowser.selectedTab.linkedBrowser.docShellIsActive; } + yield promiseWaitForCondition(waitForActive); + is(gBrowser.selectedTab.linkedBrowser.docShellIsActive, true, "Docshell should be active"); window.minimize(); - // XXX On Linux minimize/restore seem to be very very async, but - // our window.windowState changes sync.... so we can't rely on the - // latter correctly reflecting the state of the former. In - // particular, a restore() call before minimizing is done will not - // actually restore the window, but change the window state. As a - // result, just poll waiting for our expected isActive values. - waitForInactive(); -} + yield promiseWaitForCondition(waitForInactive); + is(gBrowser.selectedTab.linkedBrowser.docShellIsActive, false, "Docshell should be Inactive"); + window.restore(); + yield promiseWaitForCondition(waitForActive); + is(gBrowser.selectedTab.linkedBrowser.docShellIsActive, true, "Docshell should be active again"); +}); \ No newline at end of file From eb1836bb1ecaff703e210796a25a3eec484cd044 Mon Sep 17 00:00:00 2001 From: sajitk Date: Mon, 5 Oct 2015 04:35:00 +0200 Subject: [PATCH 154/228] Bug 1180940 - Changed return type of AudioDestinationNode::CreateAudioChannelAgent method to return errors, if any methods that it calls fail. Added code to handle the return value in AudioContext::Init(), and its callers. r=baku --- dom/audiochannel/AudioChannelAgent.cpp | 10 ++++-- dom/media/webaudio/AudioContext.cpp | 35 ++++++++++----------- dom/media/webaudio/AudioContext.h | 2 +- dom/media/webaudio/AudioDestinationNode.cpp | 20 +++++++++--- dom/media/webaudio/AudioDestinationNode.h | 2 +- 5 files changed, 41 insertions(+), 28 deletions(-) diff --git a/dom/audiochannel/AudioChannelAgent.cpp b/dom/audiochannel/AudioChannelAgent.cpp index 8c4106b91005..7d2fc35abcd4 100644 --- a/dom/audiochannel/AudioChannelAgent.cpp +++ b/dom/audiochannel/AudioChannelAgent.cpp @@ -98,13 +98,13 @@ AudioChannelAgent::InitInternal(nsIDOMWindow* aWindow, int32_t aChannelType, "Enum of channel on nsIAudioChannelAgent.idl should be the same with AudioChannelBinding.h"); if (mAudioChannelType != AUDIO_AGENT_CHANNEL_ERROR || - aChannelType > AUDIO_AGENT_CHANNEL_PUBLICNOTIFICATION || + aChannelType > AUDIO_AGENT_CHANNEL_SYSTEM || aChannelType < AUDIO_AGENT_CHANNEL_NORMAL) { return NS_ERROR_FAILURE; } if (NS_WARN_IF(!aWindow)) { - return NS_ERROR_FAILURE; + return NS_OK; } nsCOMPtr pInnerWindow = do_QueryInterface(aWindow); @@ -113,12 +113,16 @@ AudioChannelAgent::InitInternal(nsIDOMWindow* aWindow, int32_t aChannelType, nsCOMPtr topWindow; aWindow->GetScriptableTop(getter_AddRefs(topWindow)); + if (NS_WARN_IF(!topWindow)) { + return NS_OK; + } + mWindow = do_QueryInterface(topWindow); if (mWindow) { mWindow = mWindow->GetOuterWindow(); } - if (!mWindow) { + if (NS_WARN_IF(!mWindow)) { return NS_ERROR_FAILURE; } diff --git a/dom/media/webaudio/AudioContext.cpp b/dom/media/webaudio/AudioContext.cpp index cdd963634d01..ee07bf1c221e 100644 --- a/dom/media/webaudio/AudioContext.cpp +++ b/dom/media/webaudio/AudioContext.cpp @@ -117,14 +117,21 @@ AudioContext::AudioContext(nsPIDOMWindow* aWindow, } } -void +nsresult AudioContext::Init() { // We skip calling SetIsOnlyNodeForContext and the creation of the // audioChannelAgent during mDestination's constructor, because we can only // call them after mDestination has been set up. - mDestination->CreateAudioChannelAgent(); - mDestination->SetIsOnlyNodeForContext(true); + if (!mIsOffline) { + nsresult rv = mDestination->CreateAudioChannelAgent(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + mDestination->SetIsOnlyNodeForContext(true); + } + + return NS_OK; } AudioContext::~AudioContext() @@ -151,20 +158,9 @@ AudioContext::WrapObject(JSContext* aCx, JS::Handle aGivenProto) AudioContext::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv) { - nsCOMPtr window = do_QueryInterface(aGlobal.GetAsSupports()); - if (!window) { - aRv.Throw(NS_ERROR_FAILURE); - return nullptr; - } - - nsRefPtr object = - new AudioContext(window, false, - AudioChannelService::GetDefaultAudioChannel()); - object->Init(); - - RegisterWeakMemoryReporter(object); - - return object.forget(); + return AudioContext::Constructor(aGlobal, + AudioChannelService::GetDefaultAudioChannel(), + aRv); } /* static */ already_AddRefed @@ -179,7 +175,10 @@ AudioContext::Constructor(const GlobalObject& aGlobal, } nsRefPtr object = new AudioContext(window, false, aChannel); - object->Init(); + aRv = object->Init(); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } RegisterWeakMemoryReporter(object); diff --git a/dom/media/webaudio/AudioContext.h b/dom/media/webaudio/AudioContext.h index 4bed79b1be17..8e9fc32eb58d 100644 --- a/dom/media/webaudio/AudioContext.h +++ b/dom/media/webaudio/AudioContext.h @@ -124,7 +124,7 @@ class AudioContext final : public DOMEventTargetHelper, float aSampleRate = 0.0f); ~AudioContext(); - void Init(); + nsresult Init(); public: typedef uint64_t AudioContextId; diff --git a/dom/media/webaudio/AudioDestinationNode.cpp b/dom/media/webaudio/AudioDestinationNode.cpp index 9cd0a07c7d7e..1e8d9a9b3336 100644 --- a/dom/media/webaudio/AudioDestinationNode.cpp +++ b/dom/media/webaudio/AudioDestinationNode.cpp @@ -629,23 +629,33 @@ AudioDestinationNode::CheckAudioChannelPermissions(AudioChannel aValue) return perm == nsIPermissionManager::ALLOW_ACTION; } -void +nsresult AudioDestinationNode::CreateAudioChannelAgent() { if (mIsOffline) { - return; + return NS_OK; } + nsresult rv = NS_OK; if (mAudioChannelAgent) { - mAudioChannelAgent->NotifyStoppedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY); + rv = mAudioChannelAgent->NotifyStoppedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } } mAudioChannelAgent = new AudioChannelAgent(); - mAudioChannelAgent->InitWithWeakCallback(GetOwner(), + rv = mAudioChannelAgent->InitWithWeakCallback(GetOwner(), static_cast(mAudioChannel), this); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = WindowAudioCaptureChanged(); + NS_WARN_IF(NS_FAILED(rv)); + return rv; - WindowAudioCaptureChanged(); } void diff --git a/dom/media/webaudio/AudioDestinationNode.h b/dom/media/webaudio/AudioDestinationNode.h index bebed04175da..c0d1bf119f27 100644 --- a/dom/media/webaudio/AudioDestinationNode.h +++ b/dom/media/webaudio/AudioDestinationNode.h @@ -73,7 +73,7 @@ public: // When aIsOnlyNode is true, this is the only node for the AudioContext. void SetIsOnlyNodeForContext(bool aIsOnlyNode); - void CreateAudioChannelAgent(); + nsresult CreateAudioChannelAgent(); void DestroyAudioChannelAgent(); virtual const char* NodeType() const override From cbae46533ce0b8921c917171f21b92b2050b6855 Mon Sep 17 00:00:00 2001 From: Tracy Walker Date: Tue, 6 Oct 2015 07:33:52 -0500 Subject: [PATCH 155/228] Bug 1194475 - Make mixed content test cases, in browser/base/content/test/general/ more e10s friendly by using add_task() and BrowserTestUtils. r=jimm --- .../browser_mixedContentFramesOnHttp.js | 55 ++++-------- .../browser_mixedContentFromOnunload.js | 83 ++++++------------- 2 files changed, 44 insertions(+), 94 deletions(-) diff --git a/browser/base/content/test/general/browser_mixedContentFramesOnHttp.js b/browser/base/content/test/general/browser_mixedContentFramesOnHttp.js index 844bed43aef0..75603b1df2a0 100644 --- a/browser/base/content/test/general/browser_mixedContentFramesOnHttp.js +++ b/browser/base/content/test/general/browser_mixedContentFramesOnHttp.js @@ -10,44 +10,25 @@ * the HTTP top level page to broken HTTPS. */ -const gHttpTestRoot = "http://example.com/browser/browser/base/content/test/general/"; +const gHttpTestUrl = "http://example.com/browser/browser/base/content/test/general/file_mixedContentFramesOnHttp.html"; var gTestBrowser = null; -function SecStateTestsCompleted() { - gBrowser.removeCurrentTab(); - window.focus(); - finish(); -} +add_task(function *() { + yield new Promise(resolve => { + SpecialPowers.pushPrefEnv({ + "set": [ + ["security.mixed_content.block_active_content", true], + ["security.mixed_content.block_display_content", false] + ] + }, resolve); + }); + let url = gHttpTestUrl + yield BrowserTestUtils.withNewTab({gBrowser, url}, function*(){ + gTestBrowser = gBrowser.selectedBrowser; + // check security state is insecure + isSecurityState("insecure"); + assertMixedContentBlockingState(gTestBrowser, {activeLoaded: false, activeBlocked: false, passiveLoaded: true}); + }); +}); -function test() { - waitForExplicitFinish(); - SpecialPowers.pushPrefEnv({"set": [ - ["security.mixed_content.block_active_content", true], - ["security.mixed_content.block_display_content", false] - ]}, SecStateTests); -} - -function SecStateTests() { - let url = gHttpTestRoot + "file_mixedContentFramesOnHttp.html"; - gBrowser.selectedTab = gBrowser.addTab(); - gTestBrowser = gBrowser.selectedBrowser; - whenLoaded(gTestBrowser, SecStateTest1); - gTestBrowser.contentWindow.location = url; -} - -// The http page loads an https frame with an http image. -function SecStateTest1() { - // check security state is insecure - isSecurityState("insecure"); - assertMixedContentBlockingState(gTestBrowser, {activeLoaded: false, activeBlocked: false, passiveLoaded: true}); - - SecStateTestsCompleted(); -} - -function whenLoaded(aElement, aCallback) { - aElement.addEventListener("load", function onLoad() { - aElement.removeEventListener("load", onLoad, true); - executeSoon(aCallback); - }, true); -} diff --git a/browser/base/content/test/general/browser_mixedContentFromOnunload.js b/browser/base/content/test/general/browser_mixedContentFromOnunload.js index b1ce5cae4328..338f9b458fa6 100644 --- a/browser/base/content/test/general/browser_mixedContentFromOnunload.js +++ b/browser/base/content/test/general/browser_mixedContentFromOnunload.js @@ -14,67 +14,36 @@ const gHttpTestRoot2 = "http://example.net/browser/browser/base/content/test/gen const gHttpsTestRoot2 = "https://test2.example.com/browser/browser/base/content/test/general/"; var gTestBrowser = null; - -function SecStateTestsCompleted() { - gBrowser.removeCurrentTab(); - window.focus(); - finish(); -} - -function test() { - waitForExplicitFinish(); - SpecialPowers.pushPrefEnv({"set": [["security.mixed_content.block_active_content", true], - ["security.mixed_content.block_display_content", false]]}, SecStateTests); -} - -function SecStateTests() { - gBrowser.selectedTab = gBrowser.addTab(); - gTestBrowser = gBrowser.selectedBrowser; - - whenLoaded(gTestBrowser, SecStateTest1A); +add_task(function *() { let url = gHttpTestRoot1 + "file_mixedContentFromOnunload.html"; - gTestBrowser.contentWindow.location = url; -} - -// Navigation from an http page to a https page with no mixed content -// The http page loads an http image on unload -function SecStateTest1A() { - whenLoaded(gTestBrowser, SecStateTest1B); - let url = gHttpsTestRoot1 + "file_mixedContentFromOnunload_test1.html"; - gTestBrowser.contentWindow.location = url; -} - -function SecStateTest1B() { + yield BrowserTestUtils.withNewTab({gBrowser, url}, function*(){ + yield new Promise(resolve => { + SpecialPowers.pushPrefEnv({ + "set": [ + ["security.mixed_content.block_active_content", true], + ["security.mixed_content.block_display_content", false] + ] + }, resolve); + }); + gTestBrowser = gBrowser.selectedBrowser; + // Navigation from an http page to a https page with no mixed content + // The http page loads an http image on unload + url = gHttpsTestRoot1 + "file_mixedContentFromOnunload_test1.html"; + yield BrowserTestUtils.loadURI(gTestBrowser, url); + yield BrowserTestUtils.browserLoaded(gTestBrowser); // check security state. Since current url is https and doesn't have any // mixed content resources, we expect it to be secure. isSecurityState("secure"); assertMixedContentBlockingState(gTestBrowser, {activeLoaded: false, activeBlocked: false, passiveLoaded: false}); - - whenLoaded(gTestBrowser, SecStateTest2A); - - // change locations and proceed with the second test - let url = gHttpTestRoot2 + "file_mixedContentFromOnunload.html"; - gTestBrowser.contentWindow.location = url; -} - -// Navigation from an http page to a https page that has mixed display content -// The https page loads an http image on unload -function SecStateTest2A() { - whenLoaded(gTestBrowser, SecStateTest2B); - let url = gHttpsTestRoot2 + "file_mixedContentFromOnunload_test2.html"; - gTestBrowser.contentWindow.location = url; -} - -function SecStateTest2B() { + // Navigation from an http page to a https page that has mixed display content + // The https page loads an http image on unload + url = gHttpTestRoot2 + "file_mixedContentFromOnunload.html"; + yield BrowserTestUtils.loadURI(gTestBrowser, url); + yield BrowserTestUtils.browserLoaded(gTestBrowser); + url = gHttpsTestRoot2 + "file_mixedContentFromOnunload_test2.html"; + yield BrowserTestUtils.loadURI(gTestBrowser, url); + yield BrowserTestUtils.browserLoaded(gTestBrowser); isSecurityState("broken"); assertMixedContentBlockingState(gTestBrowser, {activeLoaded: false, activeBlocked: false, passiveLoaded: true}); - - SecStateTestsCompleted(); -} - -function whenLoaded(aElement, aCallback) { - aElement.addEventListener("load", function onLoad() { - aElement.removeEventListener("load", onLoad, true); - executeSoon(aCallback); - }, true); -} + }); +}); From 3e0637f43f462be97719629008984c20aa3d3db6 Mon Sep 17 00:00:00 2001 From: John Lin Date: Tue, 6 Oct 2015 02:18:00 +0200 Subject: [PATCH 156/228] Bug 1198664 - Part 1 - Refactor: move common behaviors to base class. r=bwu,jya --- .../gonk/GonkAudioDecoderManager.cpp | 86 ++---------- .../platforms/gonk/GonkAudioDecoderManager.h | 25 +--- .../platforms/gonk/GonkMediaDataDecoder.cpp | 105 ++++++++++++++- .../platforms/gonk/GonkMediaDataDecoder.h | 45 ++++++- .../gonk/GonkVideoDecoderManager.cpp | 123 ++---------------- .../platforms/gonk/GonkVideoDecoderManager.h | 47 +------ 6 files changed, 170 insertions(+), 261 deletions(-) diff --git a/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp b/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp index d964b2625203..377c47a8d6a7 100644 --- a/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp +++ b/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp @@ -34,18 +34,15 @@ typedef android::MediaCodecProxy MediaCodecProxy; namespace mozilla { GonkAudioDecoderManager::GonkAudioDecoderManager(const AudioInfo& aConfig) - : mLastDecodedTime(0) - , mAudioChannels(aConfig.mChannels) + : mAudioChannels(aConfig.mChannels) , mAudioRate(aConfig.mRate) , mAudioProfile(aConfig.mProfile) , mAudioBuffer(nullptr) - , mMonitor("GonkAudioDecoderManager") { MOZ_COUNT_CTOR(GonkAudioDecoderManager); MOZ_ASSERT(mAudioChannels); mCodecSpecificData = aConfig.mCodecSpecificConfig; mMimeType = aConfig.mMimeType; - } GonkAudioDecoderManager::~GonkAudioDecoderManager() @@ -54,9 +51,9 @@ GonkAudioDecoderManager::~GonkAudioDecoderManager() } nsRefPtr -GonkAudioDecoderManager::Init(MediaDataDecoderCallback* aCallback) +GonkAudioDecoderManager::Init() { - if (InitMediaCodecProxy(aCallback)) { + if (InitMediaCodecProxy()) { return InitPromise::CreateAndResolve(TrackType::kAudioTrack, __func__); } else { return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__); @@ -64,18 +61,14 @@ GonkAudioDecoderManager::Init(MediaDataDecoderCallback* aCallback) } bool -GonkAudioDecoderManager::InitMediaCodecProxy(MediaDataDecoderCallback* aCallback) +GonkAudioDecoderManager::InitMediaCodecProxy() { status_t rv = OK; - if (mLooper != nullptr) { + if (!InitLoopers(MediaData::AUDIO_DATA)) { return false; } - // Create ALooper - mLooper = new ALooper; - mLooper->setName("GonkAudioDecoderManager"); - mLooper->start(); - mDecoder = MediaCodecProxy::CreateByType(mLooper, mMimeType.get(), false, nullptr); + mDecoder = MediaCodecProxy::CreateByType(mDecodeLooper, mMimeType.get(), false, nullptr); if (!mDecoder.get()) { return false; } @@ -110,52 +103,6 @@ GonkAudioDecoderManager::InitMediaCodecProxy(MediaDataDecoderCallback* aCallback } } -bool -GonkAudioDecoderManager::HasQueuedSample() -{ - MonitorAutoLock mon(mMonitor); - return mQueueSample.Length(); -} - -nsresult -GonkAudioDecoderManager::Input(MediaRawData* aSample) -{ - MonitorAutoLock mon(mMonitor); - nsRefPtr sample; - - if (aSample) { - sample = aSample; - } else { - // It means EOS with empty sample. - sample = new MediaRawData(); - } - - mQueueSample.AppendElement(sample); - - status_t rv; - while (mQueueSample.Length()) { - nsRefPtr data = mQueueSample.ElementAt(0); - { - MonitorAutoUnlock mon_exit(mMonitor); - rv = mDecoder->Input(reinterpret_cast(data->Data()), - data->Size(), - data->mTime, - 0); - } - if (rv == OK) { - mQueueSample.RemoveElementAt(0); - } else if (rv == -EAGAIN || rv == -ETIMEDOUT) { - // In most cases, EAGAIN or ETIMEOUT are safe because OMX can't fill - // buffer on time. - return NS_OK; - } else { - return NS_ERROR_UNEXPECTED; - } - } - - return NS_OK; -} - nsresult GonkAudioDecoderManager::CreateAudioData(int64_t aStreamOffset, AudioData **v) { if (!(mAudioBuffer != nullptr && mAudioBuffer->data() != nullptr)) { @@ -175,13 +122,13 @@ GonkAudioDecoderManager::CreateAudioData(int64_t aStreamOffset, AudioData **v) { return NS_ERROR_NOT_AVAILABLE; } - if (mLastDecodedTime > timeUs) { + if (mLastTime > timeUs) { ReleaseAudioBuffer(); GADM_LOG("Output decoded sample time is revert. time=%lld", timeUs); MOZ_ASSERT(false); return NS_ERROR_NOT_AVAILABLE; } - mLastDecodedTime = timeUs; + mLastTime = timeUs; const uint8_t *data = static_cast(mAudioBuffer->data()); size_t dataOffset = mAudioBuffer->range_offset(); @@ -207,23 +154,6 @@ GonkAudioDecoderManager::CreateAudioData(int64_t aStreamOffset, AudioData **v) { return NS_OK; } -nsresult -GonkAudioDecoderManager::Flush() -{ - { - MonitorAutoLock mon(mMonitor); - mQueueSample.Clear(); - } - - mLastDecodedTime = 0; - - if (mDecoder->flush() != OK) { - return NS_ERROR_FAILURE; - } - - return NS_OK; -} - nsresult GonkAudioDecoderManager::Output(int64_t aStreamOffset, nsRefPtr& aOutData) diff --git a/dom/media/platforms/gonk/GonkAudioDecoderManager.h b/dom/media/platforms/gonk/GonkAudioDecoderManager.h index 4fc70f61e58f..473b03c31057 100644 --- a/dom/media/platforms/gonk/GonkAudioDecoderManager.h +++ b/dom/media/platforms/gonk/GonkAudioDecoderManager.h @@ -13,7 +13,6 @@ using namespace android; namespace android { -struct MOZ_EXPORT ALooper; class MOZ_EXPORT MediaBuffer; } // namespace android @@ -24,44 +23,26 @@ typedef android::MediaCodecProxy MediaCodecProxy; public: GonkAudioDecoderManager(const AudioInfo& aConfig); - virtual ~GonkAudioDecoderManager() override; + virtual ~GonkAudioDecoderManager(); - nsRefPtr Init(MediaDataDecoderCallback* aCallback) override; - - nsresult Input(MediaRawData* aSample) override; + nsRefPtr Init() override; nsresult Output(int64_t aStreamOffset, nsRefPtr& aOutput) override; - nsresult Flush() override; - - bool HasQueuedSample() override; - private: - bool InitMediaCodecProxy(MediaDataDecoderCallback* aCallback); + bool InitMediaCodecProxy(); nsresult CreateAudioData(int64_t aStreamOffset, AudioData** aOutData); void ReleaseAudioBuffer(); - int64_t mLastDecodedTime; - uint32_t mAudioChannels; uint32_t mAudioRate; const uint32_t mAudioProfile; - MediaDataDecoderCallback* mReaderCallback; android::MediaBuffer* mAudioBuffer; - android::sp mLooper; - - // This monitor protects mQueueSample. - Monitor mMonitor; - - // An queue with the MP4 samples which are waiting to be sent into OMX. - // If an element is an empty MP4Sample, that menas EOS. There should not - // any sample be queued after EOS. - nsTArray> mQueueSample; }; } // namespace mozilla diff --git a/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp b/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp index 40153625dcb6..e16c5de06342 100644 --- a/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp +++ b/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp @@ -8,6 +8,8 @@ #include "nsTArray.h" #include "MediaCodecProxy.h" +#include + #include "mozilla/Logging.h" #include #define GMDD_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "GonkMediaDataDecoder", __VA_ARGS__) @@ -19,6 +21,87 @@ using namespace android; namespace mozilla { +bool +GonkDecoderManager::InitLoopers(MediaData::Type aType) +{ + MOZ_ASSERT(mDecodeLooper.get() == nullptr && mTaskLooper.get() == nullptr); + MOZ_ASSERT(aType == MediaData::VIDEO_DATA || aType == MediaData::AUDIO_DATA); + + const char* suffix = (aType == MediaData::VIDEO_DATA ? "video" : "audio"); + mDecodeLooper = new ALooper; + android::AString name("MediaCodecProxy/"); + name.append(suffix); + mDecodeLooper->setName(name.c_str()); + + mTaskLooper = new ALooper; + name.setTo("GonkDecoderManager/"); + name.append(suffix); + mTaskLooper->setName(name.c_str()); + mTaskLooper->registerHandler(this); + + return mDecodeLooper->start() == OK && mTaskLooper->start() == OK; +} + +nsresult +GonkDecoderManager::Input(MediaRawData* aSample) +{ + MutexAutoLock lock(mMutex); + nsRefPtr sample; + + if (!aSample) { + // It means EOS with empty sample. + sample = new MediaRawData(); + } else { + sample = aSample; + } + + mQueuedSamples.AppendElement(sample); + + status_t rv; + while (mQueuedSamples.Length()) { + nsRefPtr data = mQueuedSamples.ElementAt(0); + { + MutexAutoUnlock unlock(mMutex); + rv = mDecoder->Input(reinterpret_cast(data->Data()), + data->Size(), + data->mTime, + 0); + } + if (rv == OK) { + mQueuedSamples.RemoveElementAt(0); + } else if (rv == -EAGAIN || rv == -ETIMEDOUT) { + // In most cases, EAGAIN or ETIMEOUT are safe because OMX can't fill + // buffer on time. + return NS_OK; + } else { + return NS_ERROR_UNEXPECTED; + } + } + + return NS_OK; +} + +nsresult +GonkDecoderManager::Flush() +{ + if (mDecoder == nullptr) { + GMDD_LOG("Decoder is not initialized"); + return NS_ERROR_UNEXPECTED; + } + { + MutexAutoLock lock(mMutex); + mQueuedSamples.Clear(); + } + + mLastTime = 0; + + if (mDecoder->flush() != OK) { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + nsresult GonkDecoderManager::Shutdown() { @@ -33,6 +116,25 @@ GonkDecoderManager::Shutdown() return NS_OK; } +bool +GonkDecoderManager::HasQueuedSample() +{ + MutexAutoLock lock(mMutex); + return mQueuedSamples.Length(); +} + +void +GonkDecoderManager::onMessageReceived(const sp &aMessage) +{ + switch (aMessage->what()) { + default: + { + TRESPASS(); + break; + } + } +} + GonkMediaDataDecoder::GonkMediaDataDecoder(GonkDecoderManager* aManager, FlushableTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback) @@ -43,6 +145,7 @@ GonkMediaDataDecoder::GonkMediaDataDecoder(GonkDecoderManager* aManager, , mDrainComplete(false) { MOZ_COUNT_CTOR(GonkMediaDataDecoder); + mManager->SetDecodeCallback(aCallback); } GonkMediaDataDecoder::~GonkMediaDataDecoder() @@ -55,7 +158,7 @@ GonkMediaDataDecoder::Init() { mDrainComplete = false; - return mManager->Init(mCallback); + return mManager->Init(); } nsresult diff --git a/dom/media/platforms/gonk/GonkMediaDataDecoder.h b/dom/media/platforms/gonk/GonkMediaDataDecoder.h index 69d5a55b2114..a327fca97887 100644 --- a/dom/media/platforms/gonk/GonkMediaDataDecoder.h +++ b/dom/media/platforms/gonk/GonkMediaDataDecoder.h @@ -7,8 +7,10 @@ #if !defined(GonkMediaDataDecoder_h_) #define GonkMediaDataDecoder_h_ #include "PlatformDecoderModule.h" +#include namespace android { +struct ALooper; class MediaCodecProxy; } // namespace android @@ -16,7 +18,7 @@ namespace mozilla { class MediaRawData; // Manage the data flow from inputting encoded data and outputting decode data. -class GonkDecoderManager { +class GonkDecoderManager : public android::AHandler { public: typedef TrackInfo::TrackType TrackType; typedef MediaDataDecoder::InitPromise InitPromise; @@ -24,10 +26,8 @@ public: virtual ~GonkDecoderManager() {} - virtual nsRefPtr Init(MediaDataDecoderCallback* aCallback) = 0; - // Add samples into OMX decoder or queue them if decoder is out of input buffer. - virtual nsresult Input(MediaRawData* aSample) = 0; + nsresult Input(MediaRawData* aSample); // Produces decoded output, it blocks until output can be produced or a timeout // is expired or until EOS. Returns NS_OK on success, or NS_ERROR_NOT_AVAILABLE @@ -37,26 +37,57 @@ public: // The overrided class should follow the same behaviour. virtual nsresult Output(int64_t aStreamOffset, nsRefPtr& aOutput) = 0; + virtual nsRefPtr Init() = 0; // Flush the queued sample. - virtual nsresult Flush() = 0; + nsresult Flush(); // Shutdown decoder and rejects the init promise. nsresult Shutdown(); // True if sample is queued. - virtual bool HasQueuedSample() = 0; + bool HasQueuedSample(); + + // Set callback for decoder events, such as requesting more input, + // returning output, or reporting error. + void SetDecodeCallback(MediaDataDecoderCallback* aCallback) + { + mDecodeCallback = aCallback; + } protected: + GonkDecoderManager() + : mMutex("GonkDecoderManager") + , mLastTime(0) + , mDecodeCallback(nullptr) + {} + + bool InitLoopers(MediaData::Type aType); + + void onMessageReceived(const android::sp &aMessage) override; + nsRefPtr mCodecSpecificData; nsAutoCString mMimeType; // MediaCodedc's wrapper that performs the decoding. android::sp mDecoder; + // Looper for mDecoder to run on. + android::sp mDecodeLooper; + // Looper to run decode tasks such as recycling output buffers. + android::sp mTaskLooper; MozPromiseHolder mInitPromise; + Mutex mMutex; // Protects mQueuedSamples. + // A queue that stores the samples waiting to be sent to mDecoder. + // Empty element means EOS and there shouldn't be any sample be queued after it. + // Samples are queued in caller's thread and dequeued in mTaskLooper. + nsTArray> mQueuedSamples; + + int64_t mLastTime; // The last decoded frame presentation time. + + MediaDataDecoderCallback* mDecodeCallback; // Reports decoder output or error. }; // Samples are decoded using the GonkDecoder (MediaCodec) @@ -101,7 +132,7 @@ private: RefPtr mTaskQueue; MediaDataDecoderCallback* mCallback; - nsAutoPtr mManager; + android::sp mManager; // The last offset into the media resource that was passed into Input(). // This is used to approximate the decoder's position in the media resource. diff --git a/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp b/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp index 474bf5b0a074..b62a0cdd7ff4 100644 --- a/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp +++ b/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp @@ -17,10 +17,7 @@ #include "stagefright/MediaBuffer.h" #include "stagefright/MetaData.h" #include "stagefright/MediaErrors.h" -#include -#include #include -#include #include "GonkNativeWindow.h" #include "GonkNativeWindowClient.h" #include "mozilla/layers/GrallocTextureClient.h" @@ -44,12 +41,9 @@ GonkVideoDecoderManager::GonkVideoDecoderManager( mozilla::layers::ImageContainer* aImageContainer, const VideoInfo& aConfig) : mImageContainer(aImageContainer) - , mReaderCallback(nullptr) - , mLastDecodedTime(0) , mColorConverterBufferSize(0) , mNativeWindow(nullptr) , mPendingReleaseItemsLock("GonkVideoDecoderManager::mPendingReleaseItemsLock") - , mMonitor("GonkVideoDecoderManager") { MOZ_COUNT_CTOR(GonkVideoDecoderManager); mMimeType = aConfig.mMimeType; @@ -64,7 +58,6 @@ GonkVideoDecoderManager::GonkVideoDecoderManager( nsIntSize frameSize(mVideoWidth, mVideoHeight); mPicture = pictureRect; mInitialFrame = frameSize; - mHandler = new MessageHandler(this); mVideoListener = new VideoResourceListener(this); } @@ -76,7 +69,7 @@ GonkVideoDecoderManager::~GonkVideoDecoderManager() } nsRefPtr -GonkVideoDecoderManager::Init(MediaDataDecoderCallback* aCallback) +GonkVideoDecoderManager::Init() { nsIntSize displaySize(mDisplayWidth, mDisplayHeight); nsIntRect pictureRect(0, 0, mVideoWidth, mVideoHeight); @@ -101,26 +94,19 @@ GonkVideoDecoderManager::Init(MediaDataDecoderCallback* aCallback) return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__); } - mReaderCallback = aCallback; - mReaderTaskQueue = AbstractThread::GetCurrent()->AsTaskQueue(); MOZ_ASSERT(mReaderTaskQueue); - if (mLooper.get() != nullptr) { + if (mDecodeLooper.get() != nullptr) { return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__); } - // Create ALooper - mLooper = new ALooper; - mManagerLooper = new ALooper; - mManagerLooper->setName("GonkVideoDecoderManager"); - // Register AMessage handler to ALooper. - mManagerLooper->registerHandler(mHandler); - // Start ALooper thread. - if (mLooper->start() != OK || mManagerLooper->start() != OK ) { + + if (!InitLoopers(MediaData::VIDEO_DATA)) { return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__); } + nsRefPtr p = mInitPromise.Ensure(__func__); - mDecoder = MediaCodecProxy::CreateByType(mLooper, mMimeType.get(), false, mVideoListener); + mDecoder = MediaCodecProxy::CreateByType(mDecodeLooper, mMimeType.get(), false, mVideoListener); mDecoder->AsyncAskMediaCodec(); uint32_t capability = MediaCodecProxy::kEmptyCapability; @@ -132,52 +118,6 @@ GonkVideoDecoderManager::Init(MediaDataDecoderCallback* aCallback) return p; } -nsresult -GonkVideoDecoderManager::Input(MediaRawData* aSample) -{ - MonitorAutoLock mon(mMonitor); - nsRefPtr sample; - - if (!aSample) { - // It means EOS with empty sample. - sample = new MediaRawData(); - } else { - sample = aSample; - } - - mQueueSample.AppendElement(sample); - - status_t rv; - while (mQueueSample.Length()) { - nsRefPtr data = mQueueSample.ElementAt(0); - { - MonitorAutoUnlock mon_unlock(mMonitor); - rv = mDecoder->Input(reinterpret_cast(data->Data()), - data->Size(), - data->mTime, - 0); - } - if (rv == OK) { - mQueueSample.RemoveElementAt(0); - } else if (rv == -EAGAIN || rv == -ETIMEDOUT) { - // In most cases, EAGAIN or ETIMEOUT are safe because OMX can't fill - // buffer on time. - return NS_OK; - } else { - return NS_ERROR_UNEXPECTED; - } - } - - return NS_OK; -} - -bool -GonkVideoDecoderManager::HasQueuedSample() -{ - MonitorAutoLock mon(mMonitor); - return mQueueSample.Length(); -} - nsresult GonkVideoDecoderManager::CreateVideoData(int64_t aStreamOffset, VideoData **v) { @@ -197,12 +137,12 @@ GonkVideoDecoderManager::CreateVideoData(int64_t aStreamOffset, VideoData **v) return NS_ERROR_UNEXPECTED; } - if (mLastDecodedTime > timeUs) { + if (mLastTime > timeUs) { ReleaseVideoBuffer(); GVDM_LOG("Output decoded sample time is revert. time=%lld", timeUs); return NS_ERROR_NOT_AVAILABLE; } - mLastDecodedTime = timeUs; + mLastTime = timeUs; if (mVideoBuffer->range_length() == 0) { // Some decoders may return spurious empty buffers that we just want to ignore @@ -367,27 +307,6 @@ GonkVideoDecoderManager::SetVideoFormat() return false; } -nsresult -GonkVideoDecoderManager::Flush() -{ - if (mDecoder == nullptr) { - GVDM_LOG("Decoder is not inited"); - return NS_ERROR_UNEXPECTED; - } - { - MonitorAutoLock mon(mMonitor); - mQueueSample.Clear(); - } - - mLastDecodedTime = 0; - - if (mDecoder->flush() != OK) { - return NS_ERROR_FAILURE; - } - - return NS_OK; -} - // Blocks until decoded sample is produced by the deoder. nsresult GonkVideoDecoderManager::Output(int64_t aStreamOffset, @@ -516,7 +435,7 @@ GonkVideoDecoderManager::codecCanceled() mInitPromise.RejectIfExists(DecoderFailureReason::CANCELED, __func__); } -// Called on GonkVideoDecoderManager::mManagerLooper thread. +// Called on GonkDecoderManager::mTaskLooper thread. void GonkVideoDecoderManager::onMessageReceived(const sp &aMessage) { @@ -528,26 +447,10 @@ GonkVideoDecoderManager::onMessageReceived(const sp &aMessage) } default: - TRESPASS(); + { + GonkDecoderManager::onMessageReceived(aMessage); break; - } -} - -GonkVideoDecoderManager::MessageHandler::MessageHandler(GonkVideoDecoderManager *aManager) - : mManager(aManager) -{ -} - -GonkVideoDecoderManager::MessageHandler::~MessageHandler() -{ - mManager = nullptr; -} - -void -GonkVideoDecoderManager::MessageHandler::onMessageReceived(const android::sp &aMessage) -{ - if (mManager != nullptr) { - mManager->onMessageReceived(aMessage); + } } } @@ -652,7 +555,7 @@ void GonkVideoDecoderManager::PostReleaseVideoBuffer( } } sp notify = - new AMessage(kNotifyPostReleaseBuffer, mHandler->id()); + new AMessage(kNotifyPostReleaseBuffer, id()); notify->post(); } diff --git a/dom/media/platforms/gonk/GonkVideoDecoderManager.h b/dom/media/platforms/gonk/GonkVideoDecoderManager.h index 925cb1846915..9a5a764dcd28 100644 --- a/dom/media/platforms/gonk/GonkVideoDecoderManager.h +++ b/dom/media/platforms/gonk/GonkVideoDecoderManager.h @@ -7,13 +7,11 @@ #if !defined(GonkVideoDecoderManager_h_) #define GonkVideoDecoderManager_h_ -#include #include "nsRect.h" #include "GonkMediaDataDecoder.h" #include "mozilla/RefPtr.h" #include "I420ColorConverterHelper.h" #include "MediaCodecProxy.h" -#include #include "GonkNativeWindow.h" #include "GonkNativeWindowClient.h" #include "mozilla/layers/FenceUtils.h" @@ -22,7 +20,6 @@ using namespace android; namespace android { -struct ALooper; class MediaBuffer; struct MOZ_EXPORT AString; class GonkNativeWindow; @@ -42,19 +39,13 @@ public: GonkVideoDecoderManager(mozilla::layers::ImageContainer* aImageContainer, const VideoInfo& aConfig); - virtual ~GonkVideoDecoderManager() override; + virtual ~GonkVideoDecoderManager(); - nsRefPtr Init(MediaDataDecoderCallback* aCallback) override; - - nsresult Input(MediaRawData* aSample) override; + nsRefPtr Init() override; nsresult Output(int64_t aStreamOffset, nsRefPtr& aOutput) override; - nsresult Flush() override; - - bool HasQueuedSample() override; - static void RecycleCallback(TextureClient* aClient, void* aClosure); private: @@ -70,23 +61,8 @@ private: int32_t mCropRight = 0; int32_t mCropBottom = 0; }; - class MessageHandler : public android::AHandler - { - public: - MessageHandler(GonkVideoDecoderManager *aManager); - ~MessageHandler(); - void onMessageReceived(const android::sp &aMessage) override; - - private: - // Forbidden - MessageHandler() = delete; - MessageHandler(const MessageHandler &rhs) = delete; - const MessageHandler &operator=(const MessageHandler &rhs) = delete; - - GonkVideoDecoderManager *mManager; - }; - friend class MessageHandler; + void onMessageReceived(const android::sp &aMessage) override; class VideoResourceListener : public android::MediaCodecProxy::CodecResourceListener { @@ -119,7 +95,6 @@ private: // For codec resource management void codecReserved(); void codecCanceled(); - void onMessageReceived(const sp &aMessage); void ReleaseAllPendingVideoBuffers(); void PostReleaseVideoBuffer(android::MediaBuffer *aBuffer, @@ -136,16 +111,10 @@ private: android::MediaBuffer* mVideoBuffer; - MediaDataDecoderCallback* mReaderCallback; MediaInfo mInfo; android::sp mVideoListener; - android::sp mHandler; - android::sp mLooper; - android::sp mManagerLooper; FrameInfo mFrameInfo; - int64_t mLastDecodedTime; // The last decoded frame presentation time. - // color converter android::I420ColorConverterHelper mColorConverter; nsAutoArrayPtr mColorConverterBuffer; @@ -168,17 +137,9 @@ private: // The lock protects mPendingReleaseItems. Mutex mPendingReleaseItemsLock; - // This monitor protects mQueueSample. - Monitor mMonitor; - - // This TaskQueue should be the same one in mReaderCallback->OnReaderTaskQueue(). + // This TaskQueue should be the same one in mDecodeCallback->OnReaderTaskQueue(). // It is for codec resource mangement, decoding task should not dispatch to it. nsRefPtr mReaderTaskQueue; - - // An queue with the MP4 samples which are waiting to be sent into OMX. - // If an element is an empty MP4Sample, that menas EOS. There should not - // any sample be queued after EOS. - nsTArray> mQueueSample; }; } // namespace mozilla From 993994a08005b289cda1d2e567949fb06f3e94e7 Mon Sep 17 00:00:00 2001 From: John Lin Date: Tue, 6 Oct 2015 02:20:00 +0200 Subject: [PATCH 157/228] Bug 1198664 - Part 2 - Use looper to process decoder tasks. r=bwu --- dom/media/omx/MediaCodecProxy.cpp | 10 +- dom/media/omx/MediaCodecProxy.h | 2 +- .../gonk/GonkAudioDecoderManager.cpp | 7 +- .../platforms/gonk/GonkMediaDataDecoder.cpp | 238 ++++++++++-------- .../platforms/gonk/GonkMediaDataDecoder.h | 79 +++--- .../gonk/GonkVideoDecoderManager.cpp | 6 +- 6 files changed, 195 insertions(+), 147 deletions(-) diff --git a/dom/media/omx/MediaCodecProxy.cpp b/dom/media/omx/MediaCodecProxy.cpp index 5e53c258a96d..5c0eec575e74 100644 --- a/dom/media/omx/MediaCodecProxy.cpp +++ b/dom/media/omx/MediaCodecProxy.cpp @@ -14,7 +14,6 @@ #include #define MCP_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "MediaCodecProxy", __VA_ARGS__) -#define TIMEOUT_DEQUEUE_INPUTBUFFER_MS 1000000ll namespace android { @@ -571,7 +570,8 @@ bool MediaCodecProxy::UpdateOutputBuffers() } status_t MediaCodecProxy::Input(const uint8_t* aData, uint32_t aDataSize, - int64_t aTimestampUsecs, uint64_t aflags) + int64_t aTimestampUsecs, uint64_t aflags, + int64_t aTimeoutUs) { // Read Lock for mCodec { @@ -583,9 +583,11 @@ status_t MediaCodecProxy::Input(const uint8_t* aData, uint32_t aDataSize, } size_t index; - status_t err = dequeueInputBuffer(&index, TIMEOUT_DEQUEUE_INPUTBUFFER_MS); + status_t err = dequeueInputBuffer(&index, aTimeoutUs); if (err != OK) { - MCP_LOG("dequeueInputBuffer returned %d", err); + if (err != -EAGAIN) { + MCP_LOG("dequeueInputBuffer returned %d", err); + } return err; } diff --git a/dom/media/omx/MediaCodecProxy.h b/dom/media/omx/MediaCodecProxy.h index 890c004128b0..b21639c20d57 100644 --- a/dom/media/omx/MediaCodecProxy.h +++ b/dom/media/omx/MediaCodecProxy.h @@ -129,7 +129,7 @@ public: // If aData is null, will notify decoder input EOS status_t Input(const uint8_t* aData, uint32_t aDataSize, - int64_t aTimestampUsecs, uint64_t flags); + int64_t aTimestampUsecs, uint64_t flags, int64_t aTimeoutUs = 0); status_t Output(MediaBuffer** aBuffer, int64_t aTimeoutUs); bool Prepare(); void ReleaseMediaResources(); diff --git a/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp b/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp index 377c47a8d6a7..131b7206fe15 100644 --- a/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp +++ b/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp @@ -21,12 +21,14 @@ #include "MediaData.h" #include "MediaInfo.h" +#define CODECCONFIG_TIMEOUT_US 10000LL +#define READ_OUTPUT_BUFFER_TIMEOUT_US 0LL + #include #define GADM_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "GonkAudioDecoderManager", __VA_ARGS__) extern PRLogModuleInfo* GetPDMLog(); #define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__)) -#define READ_OUTPUT_BUFFER_TIMEOUT_US 3000 using namespace android; typedef android::MediaCodecProxy MediaCodecProxy; @@ -92,7 +94,8 @@ GonkAudioDecoderManager::InitMediaCodecProxy() if (mMimeType.EqualsLiteral("audio/mp4a-latm")) { rv = mDecoder->Input(mCodecSpecificData->Elements(), mCodecSpecificData->Length(), 0, - android::MediaCodec::BUFFER_FLAG_CODECCONFIG); + android::MediaCodec::BUFFER_FLAG_CODECCONFIG, + CODECCONFIG_TIMEOUT_US); } if (rv == OK) { diff --git a/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp b/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp index e16c5de06342..39fbacbfa4d2 100644 --- a/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp +++ b/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp @@ -13,6 +13,8 @@ #include "mozilla/Logging.h" #include #define GMDD_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "GonkMediaDataDecoder", __VA_ARGS__) +#define INPUT_TIMEOUT_US 0LL // Don't wait for buffer if none is available. +#define MIN_QUEUED_SAMPLES 2 extern PRLogModuleInfo* GetPDMLog(); #define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__)) @@ -45,40 +47,53 @@ GonkDecoderManager::InitLoopers(MediaData::Type aType) nsresult GonkDecoderManager::Input(MediaRawData* aSample) { - MutexAutoLock lock(mMutex); nsRefPtr sample; - if (!aSample) { + if (aSample) { + sample = aSample; + } else { // It means EOS with empty sample. sample = new MediaRawData(); - } else { - sample = aSample; + } + { + MutexAutoLock lock(mMutex); + mQueuedSamples.AppendElement(sample); } - mQueuedSamples.AppendElement(sample); + sp input = new AMessage(kNotifyProcessInput, id()); + if (!aSample) { + input->setInt32("input-eos", 1); + } + input->post(); + return NS_OK; +} +int32_t +GonkDecoderManager::ProcessQueuedSample() +{ + MutexAutoLock lock(mMutex); status_t rv; while (mQueuedSamples.Length()) { nsRefPtr data = mQueuedSamples.ElementAt(0); { - MutexAutoUnlock unlock(mMutex); rv = mDecoder->Input(reinterpret_cast(data->Data()), data->Size(), data->mTime, - 0); + 0, + INPUT_TIMEOUT_US); } if (rv == OK) { mQueuedSamples.RemoveElementAt(0); + mWaitOutput.AppendElement(data->mOffset); } else if (rv == -EAGAIN || rv == -ETIMEDOUT) { // In most cases, EAGAIN or ETIMEOUT are safe because OMX can't fill // buffer on time. - return NS_OK; + break; } else { - return NS_ERROR_UNEXPECTED; + return rv; } } - - return NS_OK; + return mQueuedSamples.Length(); } nsresult @@ -95,10 +110,13 @@ GonkDecoderManager::Flush() mLastTime = 0; - if (mDecoder->flush() != OK) { - return NS_ERROR_FAILURE; + MonitorAutoLock lock(mFlushMonitor); + mIsFlushing = true; + sp flush = new AMessage(kNotifyProcessFlush, id()); + flush->post(); + while (mIsFlushing) { + lock.Wait(); } - return NS_OK; } @@ -123,10 +141,112 @@ GonkDecoderManager::HasQueuedSample() return mQueuedSamples.Length(); } +void +GonkDecoderManager::ProcessInput(bool aEndOfStream) +{ + status_t rv = ProcessQueuedSamples(); + if (rv >= 0) { + if (!aEndOfStream && rv <= MIN_QUEUED_SAMPLES) { + mDecodeCallback->InputExhausted(); + } + + if (mToDo.get() == nullptr) { + mToDo = new AMessage(kNotifyDecoderActivity, id()); + if (aEndOfStream) { + mToDo->setInt32("input-eos", 1); + } + mDecoder->requestActivityNotification(mToDo); + } + } else { + GMDD_LOG("input processed: error#%d", rv); + mDecodeCallback->Error(); + } +} + +void +GonkDecoderManager::ProcessFlush() +{ + MonitorAutoLock lock(mFlushMonitor); + mWaitOutput.Clear(); + if (mDecoder->flush() != OK) { + GMDD_LOG("flush error"); + mDecodeCallback->Error(); + } + mIsFlushing = false; + lock.NotifyAll(); +} + +void +GonkDecoderManager::ProcessToDo(bool aEndOfStream) +{ + MOZ_ASSERT(mToDo.get() != nullptr); + mToDo.clear(); + + if (HasQueuedSample()) { + status_t pendingInput = ProcessQueuedSamples(); + if (pendingInput < 0) { + mDecodeCallback->Error(); + return; + } + if (!aEndOfStream && pendingInput <= MIN_QUEUED_SAMPLES) { + mDecodeCallback->InputExhausted(); + } + } + + nsresult rv = NS_OK; + while (mWaitOutput.Length() > 0) { + nsRefPtr output; + int64_t offset = mWaitOutput.ElementAt(0); + rv = Output(offset, output); + if (rv == NS_OK) { + mWaitOutput.RemoveElementAt(0); + mDecodeCallback->Output(output); + } else if (rv == NS_ERROR_ABORT) { + GMDD_LOG("eos output"); + mWaitOutput.RemoveElementAt(0); + MOZ_ASSERT(mQueuedSamples.IsEmpty()); + MOZ_ASSERT(mWaitOutput.IsEmpty()); + // EOS + if (output) { + mDecodeCallback->Output(output); + } + mDecodeCallback->DrainComplete(); + return; + } else if (rv == NS_ERROR_NOT_AVAILABLE) { + break; + } else { + mDecodeCallback->Error(); + return; + } + } + + if (HasQueuedSample() || mWaitOutput.Length() > 0) { + mToDo = new AMessage(kNotifyDecoderActivity, id()); + mDecoder->requestActivityNotification(mToDo); + } +} + void GonkDecoderManager::onMessageReceived(const sp &aMessage) { switch (aMessage->what()) { + case kNotifyProcessInput: + { + int32_t eos = 0; + ProcessInput(aMessage->findInt32("input-eos", &eos) && eos); + break; + } + case kNotifyProcessFlush: + { + ProcessFlush(); + break; + } + case kNotifyDecoderActivity: + { + int32_t eos = 0; + ProcessToDo(aMessage->findInt32("input-eos", &eos) && eos); + break; + } default: { TRESPASS(); @@ -139,10 +259,7 @@ GonkMediaDataDecoder::GonkMediaDataDecoder(GonkDecoderManager* aManager, FlushableTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback) : mTaskQueue(aTaskQueue) - , mCallback(aCallback) , mManager(aManager) - , mSignaledEOS(false) - , mDrainComplete(false) { MOZ_COUNT_CTOR(GonkMediaDataDecoder); mManager->SetDecodeCallback(aCallback); @@ -156,8 +273,6 @@ GonkMediaDataDecoder::~GonkMediaDataDecoder() nsRefPtr GonkMediaDataDecoder::Init() { - mDrainComplete = false; - return mManager->Init(); } @@ -176,79 +291,10 @@ GonkMediaDataDecoder::Shutdown() nsresult GonkMediaDataDecoder::Input(MediaRawData* aSample) { - nsCOMPtr runnable( - NS_NewRunnableMethodWithArg>( - this, - &GonkMediaDataDecoder::ProcessDecode, - nsRefPtr(aSample))); - mTaskQueue->Dispatch(runnable.forget()); + mManager->Input(aSample); return NS_OK; } -void -GonkMediaDataDecoder::ProcessDecode(MediaRawData* aSample) -{ - nsresult rv = mManager->Input(aSample); - if (rv != NS_OK) { - NS_WARNING("GonkMediaDataDecoder failed to input data"); - GMDD_LOG("Failed to input data err: %d",int(rv)); - mCallback->Error(); - return; - } - if (aSample) { - mLastStreamOffset = aSample->mOffset; - } - ProcessOutput(); -} - -void -GonkMediaDataDecoder::ProcessOutput() -{ - nsRefPtr output; - nsresult rv = NS_ERROR_ABORT; - - while (!mDrainComplete) { - // There are samples in queue, try to send them into decoder when EOS. - if (mSignaledEOS && mManager->HasQueuedSample()) { - GMDD_LOG("ProcessOutput: drain all input samples"); - rv = mManager->Input(nullptr); - } - rv = mManager->Output(mLastStreamOffset, output); - if (rv == NS_OK) { - mCallback->Output(output); - continue; - } else if (rv == NS_ERROR_NOT_AVAILABLE && mSignaledEOS) { - // Try to get more frames before getting EOS frame - continue; - } - else { - break; - } - } - - if (rv == NS_ERROR_NOT_AVAILABLE && !mSignaledEOS) { - mCallback->InputExhausted(); - return; - } - if (rv != NS_OK) { - NS_WARNING("GonkMediaDataDecoder failed to output data"); - GMDD_LOG("Failed to output data"); - // GonkDecoderManangers report NS_ERROR_ABORT when EOS is reached. - if (rv == NS_ERROR_ABORT) { - if (output) { - mCallback->Output(output); - } - mCallback->DrainComplete(); - MOZ_ASSERT_IF(mSignaledEOS, !mManager->HasQueuedSample()); - mSignaledEOS = false; - mDrainComplete = true; - return; - } - GMDD_LOG("Callback error!"); - mCallback->Error(); - } -} - nsresult GonkMediaDataDecoder::Flush() { @@ -257,25 +303,13 @@ GonkMediaDataDecoder::Flush() // it's executing at all. Note the MP4Reader ignores all output while // flushing. mTaskQueue->Flush(); - mDrainComplete = false; return mManager->Flush(); } -void -GonkMediaDataDecoder::ProcessDrain() -{ - // Notify decoder input EOS by sending a null data. - ProcessDecode(nullptr); - mSignaledEOS = true; - ProcessOutput(); -} - nsresult GonkMediaDataDecoder::Drain() { - nsCOMPtr runnable = - NS_NewRunnableMethod(this, &GonkMediaDataDecoder::ProcessDrain); - mTaskQueue->Dispatch(runnable.forget()); + mManager->Input(nullptr); return NS_OK; } diff --git a/dom/media/platforms/gonk/GonkMediaDataDecoder.h b/dom/media/platforms/gonk/GonkMediaDataDecoder.h index a327fca97887..282dafbe631c 100644 --- a/dom/media/platforms/gonk/GonkMediaDataDecoder.h +++ b/dom/media/platforms/gonk/GonkMediaDataDecoder.h @@ -26,19 +26,12 @@ public: virtual ~GonkDecoderManager() {} - // Add samples into OMX decoder or queue them if decoder is out of input buffer. - nsresult Input(MediaRawData* aSample); - - // Produces decoded output, it blocks until output can be produced or a timeout - // is expired or until EOS. Returns NS_OK on success, or NS_ERROR_NOT_AVAILABLE - // if there's not enough data to produce more output. If this returns a failure - // code other than NS_ERROR_NOT_AVAILABLE, an error will be reported to the - // MP4Reader. - // The overrided class should follow the same behaviour. - virtual nsresult Output(int64_t aStreamOffset, - nsRefPtr& aOutput) = 0; virtual nsRefPtr Init() = 0; + // Asynchronously send sample into mDecoder. If out of input buffer, aSample + // will be queued for later re-send. + nsresult Input(MediaRawData* aSample); + // Flush the queued sample. nsresult Flush(); @@ -59,6 +52,8 @@ protected: GonkDecoderManager() : mMutex("GonkDecoderManager") , mLastTime(0) + , mFlushMonitor("GonkDecoderManager::Flush") + , mIsFlushing(false) , mDecodeCallback(nullptr) {} @@ -66,6 +61,21 @@ protected: void onMessageReceived(const android::sp &aMessage) override; + // Produces decoded output. It returns NS_OK on success, or NS_ERROR_NOT_AVAILABLE + // when output is not produced yet. + // If this returns a failure code other than NS_ERROR_NOT_AVAILABLE, an error + // will be reported through mDecodeCallback. + virtual nsresult Output(int64_t aStreamOffset, + nsRefPtr& aOutput) = 0; + + // Send queued samples to OMX. It returns how many samples are still in + // queue after processing, or negtive error code if failed. + int32_t ProcessQueuedSamples(); + + void ProcessInput(bool aEndOfStream); + void ProcessFlush(); + void ProcessToDo(bool aEndOfStream); + nsRefPtr mCodecSpecificData; nsAutoCString mMimeType; @@ -74,8 +84,18 @@ protected: android::sp mDecoder; // Looper for mDecoder to run on. android::sp mDecodeLooper; - // Looper to run decode tasks such as recycling output buffers. + // Looper to run decode tasks such as processing input, output, flush, and + // recycling output buffers. android::sp mTaskLooper; + enum { + // Decoder will send this to indicate internal state change such as input or + // output buffers availability. Used to run pending input & output tasks. + kNotifyDecoderActivity = 'nda ', + // Signal the decoder to flush. + kNotifyProcessFlush = 'npf ', + // Used to process queued samples when there is new input. + kNotifyProcessInput = 'npi ', + }; MozPromiseHolder mInitPromise; @@ -87,6 +107,17 @@ protected: int64_t mLastTime; // The last decoded frame presentation time. + Monitor mFlushMonitor; // Waits for flushing to complete. + bool mIsFlushing; + + // Remembers the notification that is currently waiting for the decoder event + // to avoid requesting more than one notification at the time, which is + // forbidden by mDecoder. + android::sp mToDo; + + // Stores the offset of every output that needs to be read from mDecoder. + nsTArray mWaitOutput; + MediaDataDecoderCallback* mDecodeCallback; // Reports decoder output or error. }; @@ -114,33 +145,9 @@ public: nsresult Shutdown() override; private: - - // Called on the task queue. Inserts the sample into the decoder, and - // extracts output if available, if aSample is null, it means there is - // no data from source, it will notify the decoder EOS and flush all the - // decoded frames. - void ProcessDecode(MediaRawData* aSample); - - // Called on the task queue. Extracts output if available, and delivers - // it to the reader. Called after ProcessDecode() and ProcessDrain(). - void ProcessOutput(); - - // Called on the task queue. Orders the Gonk to drain, and then extracts - // all available output. - void ProcessDrain(); - RefPtr mTaskQueue; - MediaDataDecoderCallback* mCallback; android::sp mManager; - - // The last offset into the media resource that was passed into Input(). - // This is used to approximate the decoder's position in the media resource. - int64_t mLastStreamOffset; - // Set it ture when there is no input data - bool mSignaledEOS; - // Set if there is no more output data from decoder - bool mDrainComplete; }; } // namespace mozilla diff --git a/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp b/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp index b62a0cdd7ff4..6ea7518b6ea7 100644 --- a/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp +++ b/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp @@ -24,7 +24,8 @@ #include "mozilla/layers/TextureClient.h" #include -#define READ_OUTPUT_BUFFER_TIMEOUT_US 3000 +#define CODECCONFIG_TIMEOUT_US 10000LL +#define READ_OUTPUT_BUFFER_TIMEOUT_US 0LL #include #define GVDM_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "GonkVideoDecoderManager", __VA_ARGS__) @@ -416,7 +417,8 @@ GonkVideoDecoderManager::codecReserved() if (mMimeType.EqualsLiteral("video/mp4v-es")) { rv = mDecoder->Input(mCodecSpecificData->Elements(), mCodecSpecificData->Length(), 0, - android::MediaCodec::BUFFER_FLAG_CODECCONFIG); + android::MediaCodec::BUFFER_FLAG_CODECCONFIG, + CODECCONFIG_TIMEOUT_US); } if (rv != OK) { From 8ba5de483c37190f5d7fd080f4a35d1ba0351114 Mon Sep 17 00:00:00 2001 From: Martin Thomson Date: Mon, 5 Oct 2015 13:07:33 -0700 Subject: [PATCH 158/228] Bug 1209744 - Switch to setIdentityProvider for js-implemented bindings test, r=jib --HG-- extra : transplant_source : %05%2C%E2%F4%89O%18%22r%29Q%22%3E%171%A6%FCMy%C9 --- dom/bindings/test/mochitest.ini | 1 + .../test_exceptions_from_jsimplemented.html | 28 +++++++++---------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/dom/bindings/test/mochitest.ini b/dom/bindings/test/mochitest.ini index 11285070d318..2f6b42d39c98 100644 --- a/dom/bindings/test/mochitest.ini +++ b/dom/bindings/test/mochitest.ini @@ -39,6 +39,7 @@ skip-if = debug == false [test_interfaceToString.html] [test_exceptions_from_jsimplemented.html] skip-if = (toolkit == 'gonk' && debug) #debug-only failure; bug 926547 +tags = webrtc [test_lenientThis.html] [test_lookupGetter.html] [test_namedNoIndexed.html] diff --git a/dom/bindings/test/test_exceptions_from_jsimplemented.html b/dom/bindings/test/test_exceptions_from_jsimplemented.html index b893e12c27d8..d0f599353aaf 100644 --- a/dom/bindings/test/test_exceptions_from_jsimplemented.html +++ b/dom/bindings/test/test_exceptions_from_jsimplemented.html @@ -12,27 +12,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=923010 /** Test for Bug 923010 **/ try { var conn = new RTCPeerConnection(); - try { - conn.updateIce(candidate, function() { - ok(false, "The call to updateIce succeeded when it should have thrown"); - }, function() { - ok(false, "The call to updateIce failed when it should have thrown"); - }) - ok(false, "That call to updateIce should have thrown"); - } catch (e) { - is(e.lineNumber, 16, "Exception should have been on line 16"); - is(e.message, - "updateIce not yet implemented", - "Should have the exception we expect"); - } var candidate = new RTCIceCandidate({candidate: null }); - conn.addIceCandidate(candidate) .then(function() { ok(false, "addIceCandidate succeeded when it should have failed"); }, function(reason) { - is(reason.lineNumber, 31, "Rejection should have been on line 31"); + is(reason.lineNumber, 17, "Rejection should have been on line 17"); is(reason.message, "Invalid candidate passed to addIceCandidate!", "Should have the rejection we expect"); @@ -44,6 +30,18 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=923010 // b2g has no WebRTC, apparently todo(false, "No WebRTC on b2g yet"); } + + conn.close(); + try { + conn.setIdentityProvider("example.com", "foo"); + ok(false, "That call to setIdentityProvider should have thrown"); + } catch (e) { + is(e.lineNumber, 36, "Exception should have been on line 36"); + is(e.message, + "Peer connection is closed", + "Should have the exception we expect"); + } + From 61cd22ad236b3ee733cec3a0a6b0da06e5cc9bb9 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Sat, 3 Oct 2015 20:42:26 -0400 Subject: [PATCH 159/228] Bug 1210852 - do SelectSettings of device capabilities on media thread. r=jesup --HG-- extra : transplant_source : %8E%BB%7B%90MSt%0F%40s%8A%0C/%16y%15Ne%2A%1E --- dom/media/MediaManager.cpp | 228 +++++++++++++++----------- dom/media/MediaManager.h | 6 + dom/media/systemservices/MediaUtils.h | 35 ++++ 3 files changed, 172 insertions(+), 97 deletions(-) diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index 93acc2098d03..14414e5fde6a 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -1133,46 +1133,72 @@ GetSources(MediaEngine *engine, dom::MediaSourceEnum aSrcType, } } -static const char* -SelectSettings(MediaStreamConstraints &aConstraints, - nsTArray>& aSources) +// TODO: Remove once upgraded to GCC 4.8+ on linux. Bogus error on static func: +// error: 'this' was not captured for this lambda function + +static auto& MediaManager_GetInstance = MediaManager::GetInstance; +static auto& MediaManager_ToJSArray = MediaManager::ToJSArray; +static auto& MediaManager_AnonymizeDevices = MediaManager::AnonymizeDevices; + +already_AddRefed +MediaManager::SelectSettings( + MediaStreamConstraints& aConstraints, + nsRefPtr>>& aSources) { - // Since the advanced part of the constraints algorithm needs to know when - // a candidate set is overconstrained (zero members), we must split up the - // list into videos and audios, and put it back together again at the end. + MOZ_ASSERT(NS_IsMainThread()); + nsRefPtr p = new PledgeChar(); + uint32_t id = mOutstandingCharPledges.Append(*p); - nsTArray> videos; - nsTArray> audios; + // Algorithm accesses device capabilities code and must run on media thread. + // Modifies passed-in aSources. - for (auto& source : aSources) { - if (source->mIsVideo) { - nsRefPtr video = static_cast(source.get()); - videos.AppendElement(video); - } else { - nsRefPtr audio = static_cast(source.get()); - audios.AppendElement(audio); + MediaManager::PostTask(FROM_HERE, NewTaskFrom([id, aConstraints, + aSources]() mutable { + auto& sources = **aSources; + + // Since the advanced part of the constraints algorithm needs to know when + // a candidate set is overconstrained (zero members), we must split up the + // list into videos and audios, and put it back together again at the end. + + nsTArray> videos; + nsTArray> audios; + + for (auto& source : sources) { + if (source->mIsVideo) { + nsRefPtr video = static_cast(source.get()); + videos.AppendElement(video); + } else { + nsRefPtr audio = static_cast(source.get()); + audios.AppendElement(audio); + } } - } - aSources.Clear(); - MOZ_ASSERT(!aSources.Length()); + sources.Clear(); + const char* badConstraint = nullptr; - const char* badConstraint = nullptr; - - if (IsOn(aConstraints.mVideo)) { - badConstraint = MediaConstraintsHelper::SelectSettings( - GetInvariant(aConstraints.mVideo), videos); - for (auto& video : videos) { - aSources.AppendElement(video); + if (IsOn(aConstraints.mVideo)) { + badConstraint = MediaConstraintsHelper::SelectSettings( + GetInvariant(aConstraints.mVideo), videos); + for (auto& video : videos) { + sources.AppendElement(video); + } } - } - if (audios.Length() && IsOn(aConstraints.mAudio)) { - badConstraint = MediaConstraintsHelper::SelectSettings( - GetInvariant(aConstraints.mAudio), audios); - for (auto& audio : audios) { - aSources.AppendElement(audio); + if (audios.Length() && IsOn(aConstraints.mAudio)) { + badConstraint = MediaConstraintsHelper::SelectSettings( + GetInvariant(aConstraints.mAudio), audios); + for (auto& audio : audios) { + sources.AppendElement(audio); + } } - } - return badConstraint; + NS_DispatchToMainThread(do_AddRef(NewRunnableFrom([id, badConstraint]() mutable { + nsRefPtr mgr = MediaManager_GetInstance(); + nsRefPtr p = mgr->mOutstandingCharPledges.Remove(id); + if (p) { + p->Resolve(badConstraint); + } + return NS_OK; + }))); + })); + return p.forget(); } /** @@ -1373,13 +1399,6 @@ private: }; #endif -// TODO: Remove once upgraded to GCC 4.8+ on linux. Bogus error on static func: -// error: 'this' was not captured for this lambda function - -static auto& MediaManager_GetInstance = MediaManager::GetInstance; -static auto& MediaManager_ToJSArray = MediaManager::ToJSArray; -static auto& MediaManager_AnonymizeDevices = MediaManager::AnonymizeDevices; - /** * EnumerateRawDevices - Enumerate a list of audio & video devices that * satisfy passed-in constraints. List contains raw id's. @@ -2026,80 +2045,95 @@ MediaManager::GetUserMedia(nsPIDOMWindow* aWindow, fakeTracks); p->Then([this, onSuccess, onFailure, windowID, c, listener, askPermission, prefs, isHTTPS, callID, origin](SourceSet*& aDevices) mutable { - ScopedDeletePtr devices(aDevices); // grab result - // Ensure this pointer is still valid, and window is still alive. - nsRefPtr mgr = MediaManager::GetInstance(); - nsRefPtr window = static_cast - (nsGlobalWindow::GetInnerWindowWithId(windowID)); - if (!mgr || !window) { + nsRefPtr>> devices( + new Refcountable>(aDevices)); // grab result + + // Ensure that the captured 'this' pointer and our windowID are still good. + if (!MediaManager::Exists() || + !nsGlobalWindow::GetInnerWindowWithId(windowID)) { return; } - // Apply any constraints. This modifies the list. - const char* badConstraint = SelectSettings(c, *devices); - if (badConstraint) { - nsString constraint; - constraint.AssignASCII(badConstraint); - nsRefPtr error = - new MediaStreamError(window, - NS_LITERAL_STRING("OverconstrainedError"), - NS_LITERAL_STRING(""), - constraint); - onFailure->OnError(error); - return; - } - if (!devices->Length()) { - nsRefPtr error = - new MediaStreamError(window, NS_LITERAL_STRING("NotFoundError")); - onFailure->OnError(error); - return; - } + // Apply any constraints. This modifies the passed-in list. + nsRefPtr p2 = SelectSettings(c, devices); - nsCOMPtr devicesCopy; // before we give up devices below - if (!askPermission) { - nsresult rv = NS_NewISupportsArray(getter_AddRefs(devicesCopy)); - if (NS_WARN_IF(NS_FAILED(rv))) { + p2->Then([this, onSuccess, onFailure, windowID, c, + listener, askPermission, prefs, isHTTPS, + callID, origin, devices](const char*& badConstraint) mutable { + + // Ensure that the captured 'this' pointer and our windowID are still good. + nsRefPtr window = static_cast + (nsGlobalWindow::GetInnerWindowWithId(windowID)); + if (!MediaManager::Exists() || !window) { return; } - for (auto& device : *devices) { - rv = devicesCopy->AppendElement(device); + + if (badConstraint) { + nsString constraint; + constraint.AssignASCII(badConstraint); + nsRefPtr error = + new MediaStreamError(window, + NS_LITERAL_STRING("OverconstrainedError"), + NS_LITERAL_STRING(""), + constraint); + onFailure->OnError(error); + return; + } + if (!(*devices)->Length()) { + nsRefPtr error = + new MediaStreamError(window, NS_LITERAL_STRING("NotFoundError")); + onFailure->OnError(error); + return; + } + + nsCOMPtr devicesCopy; // before we give up devices below + if (!askPermission) { + nsresult rv = NS_NewISupportsArray(getter_AddRefs(devicesCopy)); if (NS_WARN_IF(NS_FAILED(rv))) { return; } + for (auto& device : **devices) { + rv = devicesCopy->AppendElement(device); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + } } - } - // Pass callbacks and MediaStreamListener along to GetUserMediaTask. - nsAutoPtr task (new GetUserMediaTask(c, onSuccess.forget(), - onFailure.forget(), - windowID, listener, - prefs, origin, - devices.forget())); - // Store the task w/callbacks. - mActiveCallbacks.Put(callID, task.forget()); + // Pass callbacks and MediaStreamListener along to GetUserMediaTask. + nsAutoPtr task (new GetUserMediaTask(c, onSuccess.forget(), + onFailure.forget(), + windowID, listener, + prefs, origin, + devices->forget())); + // Store the task w/callbacks. + mActiveCallbacks.Put(callID, task.forget()); - // Add a WindowID cross-reference so OnNavigation can tear things down - nsTArray* array; - if (!mCallIds.Get(windowID, &array)) { - array = new nsTArray(); - mCallIds.Put(windowID, array); - } - array->AppendElement(callID); + // Add a WindowID cross-reference so OnNavigation can tear things down + nsTArray* array; + if (!mCallIds.Get(windowID, &array)) { + array = new nsTArray(); + mCallIds.Put(windowID, array); + } + array->AppendElement(callID); - nsCOMPtr obs = services::GetObserverService(); - if (!askPermission) { - obs->NotifyObservers(devicesCopy, "getUserMedia:privileged:allow", - callID.BeginReading()); - } else { - nsRefPtr req = - new GetUserMediaRequest(window, callID, c, isHTTPS); - obs->NotifyObservers(req, "getUserMedia:request", nullptr); - } + nsCOMPtr obs = services::GetObserverService(); + if (!askPermission) { + obs->NotifyObservers(devicesCopy, "getUserMedia:privileged:allow", + callID.BeginReading()); + } else { + nsRefPtr req = + new GetUserMediaRequest(window, callID, c, isHTTPS); + obs->NotifyObservers(req, "getUserMedia:request", nullptr); + } #ifdef MOZ_WEBRTC - EnableWebRtcLog(); + EnableWebRtcLog(); #endif + }, [onFailure](MediaStreamError*& reason) mutable { + onFailure->OnError(reason); + }); }, [onFailure](MediaStreamError*& reason) mutable { onFailure->OnError(reason); }); diff --git a/dom/media/MediaManager.h b/dom/media/MediaManager.h index ab00e263dfa8..d4f259bd7db6 100644 --- a/dom/media/MediaManager.h +++ b/dom/media/MediaManager.h @@ -474,6 +474,7 @@ public: static bool IsPrivateBrowsing(nsPIDOMWindow *window); private: typedef media::Pledge PledgeSourceSet; + typedef media::Pledge PledgeChar; static bool IsPrivileged(); static bool IsLoop(nsIURI* aDocURI); @@ -493,6 +494,10 @@ private: dom::MediaSourceEnum aVideoSrcType, dom::MediaSourceEnum aAudioSrcType, bool aFake = false, bool aFakeTracks = false); + already_AddRefed + SelectSettings( + dom::MediaStreamConstraints& aConstraints, + nsRefPtr>>& aSources); StreamListeners* AddWindowID(uint64_t aWindowId); WindowTable *GetActiveWindows() { @@ -533,6 +538,7 @@ private: static StaticRefPtr sSingleton; media::CoatCheck mOutstandingPledges; + media::CoatCheck mOutstandingCharPledges; media::CoatCheck mOutstandingVoidPledges; #if defined(MOZ_B2G_CAMERA) && defined(MOZ_WIDGET_GONK) nsRefPtr mCameraManager; diff --git a/dom/media/systemservices/MediaUtils.h b/dom/media/systemservices/MediaUtils.h index a89316b6d3ee..bda56d81839e 100644 --- a/dom/media/systemservices/MediaUtils.h +++ b/dom/media/systemservices/MediaUtils.h @@ -322,6 +322,41 @@ private: nsAutoTArray mElements; }; +/* media::Refcountable - Add threadsafe ref-counting to something that isn't. + * + * Often, reference counting is the most practical way to share an object with + * another thread without imposing lifetime restrictions, even if there's + * otherwise no concurrent access happening on the object. For instance, an + * algorithm on another thread may find it more expedient to modify a passed-in + * object, rather than pass expensive copies back and forth. + * + * Lists in particular often aren't ref-countable, yet are expensive to copy, + * e.g. nsTArray>. Refcountable can be used to make such objects + * (or owning smart-pointers to such objects) refcountable. + * + * Technical limitation: A template specialization is needed for types that take + * a constructor. Please add below (ScopedDeletePtr covers a lot of ground though). + */ + +template +class Refcountable : public T +{ +public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Refcountable) +private: + ~Refcountable() {} +}; + +template +class Refcountable> : public ScopedDeletePtr +{ +public: + explicit Refcountable>(T* aPtr) : ScopedDeletePtr(aPtr) {} + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Refcountable) +private: + ~Refcountable>() {} +}; + } // namespace media } // namespace mozilla From 5b977ec21d6ec1baef9ff8e7b85ec205f34d7218 Mon Sep 17 00:00:00 2001 From: Gerald Squelart Date: Mon, 5 Oct 2015 04:14:00 +0200 Subject: [PATCH 160/228] Bug 1211337 - Added crash report annotations tracking sync shutdown process. r=cpearce --- dom/media/gmp/GMPServiceParent.cpp | 35 ++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/dom/media/gmp/GMPServiceParent.cpp b/dom/media/gmp/GMPServiceParent.cpp index 9b44eb04023b..4a1abe974abe 100644 --- a/dom/media/gmp/GMPServiceParent.cpp +++ b/dom/media/gmp/GMPServiceParent.cpp @@ -267,16 +267,28 @@ GeckoMediaPluginServiceParent::Observe(nsISupports* aSubject, if (gmpThread) { LOGD(("%s::%s Starting to unload plugins, waiting for first sync shutdown..." , __CLASS__, __FUNCTION__)); +#ifdef MOZ_CRASHREPORTER + SetAsyncShutdownPluginState(nullptr, '0', + NS_LITERAL_CSTRING("Dispatching UnloadPlugins")); +#endif gmpThread->Dispatch( NS_NewRunnableMethod(this, &GeckoMediaPluginServiceParent::UnloadPlugins), NS_DISPATCH_NORMAL); +#ifdef MOZ_CRASHREPORTER + SetAsyncShutdownPluginState(nullptr, '1', + NS_LITERAL_CSTRING("Waiting for sync shutdown")); +#endif // Wait for UnloadPlugins() to do initial sync shutdown... while (mWaitingForPluginsSyncShutdown) { NS_ProcessNextEvent(NS_GetCurrentThread(), true); } +#ifdef MOZ_CRASHREPORTER + SetAsyncShutdownPluginState(nullptr, '4', + NS_LITERAL_CSTRING("Waiting for async shutdown")); +#endif // Wait for other plugins (if any) to do async shutdown... auto syncShutdownPluginsRemaining = std::numeric_limits::max(); @@ -311,6 +323,10 @@ GeckoMediaPluginServiceParent::Observe(nsISupports* aSubject, } NS_ProcessNextEvent(NS_GetCurrentThread(), true); } +#ifdef MOZ_CRASHREPORTER + SetAsyncShutdownPluginState(nullptr, '5', + NS_LITERAL_CSTRING("Async shutdown complete")); +#endif } else { // GMP thread has already shutdown. MOZ_ASSERT(mPlugins.IsEmpty()); @@ -413,6 +429,13 @@ GeckoMediaPluginServiceParent::SetAsyncShutdownPluginState(GMPParent* aGMPParent const nsCString& aState) { MutexAutoLock lock(mAsyncShutdownPluginStatesMutex); + if (!aGMPParent) { + mAsyncShutdownPluginStates.Update(NS_LITERAL_CSTRING("-"), + NS_LITERAL_CSTRING("-"), + aId, + aState); + return; + } mAsyncShutdownPluginStates.Update(aGMPParent->GetDisplayName(), nsPrintfCString("%p", aGMPParent), aId, @@ -479,6 +502,10 @@ GeckoMediaPluginServiceParent::UnloadPlugins() MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread); MOZ_ASSERT(!mShuttingDownOnGMPThread); mShuttingDownOnGMPThread = true; +#ifdef MOZ_CRASHREPORTER + SetAsyncShutdownPluginState(nullptr, '2', + NS_LITERAL_CSTRING("Starting to unload plugins")); +#endif { MutexAutoLock lock(mMutex); @@ -497,11 +524,19 @@ GeckoMediaPluginServiceParent::UnloadPlugins() // Note: CloseActive may be async; it could actually finish // shutting down when all the plugins have unloaded. for (size_t i = 0; i < mPlugins.Length(); i++) { +#ifdef MOZ_CRASHREPORTER + SetAsyncShutdownPluginState(mPlugins[i], 'S', + NS_LITERAL_CSTRING("CloseActive")); +#endif mPlugins[i]->CloseActive(true); } mPlugins.Clear(); } +#ifdef MOZ_CRASHREPORTER + SetAsyncShutdownPluginState(nullptr, '3', + NS_LITERAL_CSTRING("Dispatching sync-shutdown-complete")); +#endif nsCOMPtr task(NS_NewRunnableMethod( this, &GeckoMediaPluginServiceParent::NotifySyncShutdownComplete)); NS_DispatchToMainThread(task); From 60a48742e451ea49090c834a9f8acdc4aae08165 Mon Sep 17 00:00:00 2001 From: Gerald Squelart Date: Tue, 6 Oct 2015 14:24:00 +0200 Subject: [PATCH 161/228] Bug 1211741 - Remove libstagefright ID3 files. r=k17e --- media/libstagefright/additional_headers | 1 - .../av/media/libstagefright/id3/ID3.cpp | 903 ------------------ .../av/media/libstagefright/include/ID3.h | 102 -- media/libstagefright/moz.build | 1 - 4 files changed, 1007 deletions(-) delete mode 100644 media/libstagefright/frameworks/av/media/libstagefright/id3/ID3.cpp delete mode 100644 media/libstagefright/frameworks/av/media/libstagefright/include/ID3.h diff --git a/media/libstagefright/additional_headers b/media/libstagefright/additional_headers index fd1cefb6467c..1357302f65ba 100644 --- a/media/libstagefright/additional_headers +++ b/media/libstagefright/additional_headers @@ -13,7 +13,6 @@ frameworks/av/include/media/stagefright/MediaSource.h frameworks/av/include/media/stagefright/MetaData.h frameworks/av/include/media/stagefright/MetaData.h frameworks/av/media/libstagefright/include/ESDS.h -frameworks/av/media/libstagefright/include/ID3.h frameworks/av/media/libstagefright/include/MPEG4Extractor.h frameworks/av/media/libstagefright/include/SampleTable.h frameworks/av/media/libstagefright/include/SampleTable.h diff --git a/media/libstagefright/frameworks/av/media/libstagefright/id3/ID3.cpp b/media/libstagefright/frameworks/av/media/libstagefright/id3/ID3.cpp deleted file mode 100644 index 3aa395c55876..000000000000 --- a/media/libstagefright/frameworks/av/media/libstagefright/id3/ID3.cpp +++ /dev/null @@ -1,903 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -//#define LOG_NDEBUG 0 -#undef LOG_TAG -#define LOG_TAG "ID3" -#include - -#include "../include/ID3.h" - -#include -#include -#include -#include -#include - -namespace stagefright { - -static const size_t kMaxMetadataSize = 3 * 1024 * 1024; - -struct MemorySource : public DataSource { - MemorySource(const uint8_t *data, size_t size) - : mData(data), - mSize(size) { - } - - virtual status_t initCheck() const { - return OK; - } - - virtual ssize_t readAt(off64_t offset, void *data, size_t size) { - off64_t available = (offset >= mSize) ? 0ll : mSize - offset; - - size_t copy = (available > size) ? size : available; - memcpy(data, mData + offset, copy); - - return copy; - } - -private: - const uint8_t *mData; - size_t mSize; - - DISALLOW_EVIL_CONSTRUCTORS(MemorySource); -}; - -ID3::ID3(const sp &source, bool ignoreV1) - : mIsValid(false), - mData(NULL), - mSize(0), - mFirstFrameOffset(0), - mVersion(ID3_UNKNOWN), - mRawSize(0) { - mIsValid = parseV2(source); - - if (!mIsValid && !ignoreV1) { - mIsValid = parseV1(source); - } -} - -ID3::ID3(const uint8_t *data, size_t size, bool ignoreV1) - : mIsValid(false), - mData(NULL), - mSize(0), - mFirstFrameOffset(0), - mVersion(ID3_UNKNOWN), - mRawSize(0) { - sp source = new MemorySource(data, size); - - mIsValid = parseV2(source); - - if (!mIsValid && !ignoreV1) { - mIsValid = parseV1(source); - } -} - -ID3::~ID3() { - if (mData) { - free(mData); - mData = NULL; - } -} - -bool ID3::isValid() const { - return mIsValid; -} - -ID3::Version ID3::version() const { - return mVersion; -} - -// static -bool ID3::ParseSyncsafeInteger(const uint8_t encoded[4], size_t *x) { - *x = 0; - for (int32_t i = 0; i < 4; ++i) { - if (encoded[i] & 0x80) { - return false; - } - - *x = ((*x) << 7) | encoded[i]; - } - - return true; -} - -bool ID3::parseV2(const sp &source) { -struct id3_header { - char id[3]; - uint8_t version_major; - uint8_t version_minor; - uint8_t flags; - uint8_t enc_size[4]; - }; - - id3_header header; - if (source->readAt( - 0, &header, sizeof(header)) != (ssize_t)sizeof(header)) { - return false; - } - - if (memcmp(header.id, "ID3", 3)) { - return false; - } - - if (header.version_major == 0xff || header.version_minor == 0xff) { - return false; - } - - if (header.version_major == 2) { - if (header.flags & 0x3f) { - // We only support the 2 high bits, if any of the lower bits are - // set, we cannot guarantee to understand the tag format. - return false; - } - - if (header.flags & 0x40) { - // No compression scheme has been decided yet, ignore the - // tag if compression is indicated. - - return false; - } - } else if (header.version_major == 3) { - if (header.flags & 0x1f) { - // We only support the 3 high bits, if any of the lower bits are - // set, we cannot guarantee to understand the tag format. - return false; - } - } else if (header.version_major == 4) { - if (header.flags & 0x0f) { - // The lower 4 bits are undefined in this spec. - return false; - } - } else { - return false; - } - - size_t size; - if (!ParseSyncsafeInteger(header.enc_size, &size)) { - return false; - } - - if (size > kMaxMetadataSize) { - ALOGE("skipping huge ID3 metadata of size %d", size); - return false; - } - - mData = (uint8_t *)malloc(size); - - if (mData == NULL) { - return false; - } - - mSize = size; - mRawSize = mSize + sizeof(header); - - if (source->readAt(sizeof(header), mData, mSize) != (ssize_t)mSize) { - free(mData); - mData = NULL; - - return false; - } - - if (header.version_major == 4) { - void *copy = malloc(size); - memcpy(copy, mData, size); - - bool success = removeUnsynchronizationV2_4(false /* iTunesHack */); - if (!success) { - memcpy(mData, copy, size); - mSize = size; - - success = removeUnsynchronizationV2_4(true /* iTunesHack */); - - if (success) { - ALOGV("Had to apply the iTunes hack to parse this ID3 tag"); - } - } - - free(copy); - copy = NULL; - - if (!success) { - free(mData); - mData = NULL; - - return false; - } - } else if (header.flags & 0x80) { - ALOGV("removing unsynchronization"); - - removeUnsynchronization(); - } - - mFirstFrameOffset = 0; - if (header.version_major == 3 && (header.flags & 0x40)) { - // Version 2.3 has an optional extended header. - - if (mSize < 4) { - free(mData); - mData = NULL; - - return false; - } - - size_t extendedHeaderSize = U32_AT(&mData[0]) + 4; - - if (extendedHeaderSize > mSize) { - free(mData); - mData = NULL; - - return false; - } - - mFirstFrameOffset = extendedHeaderSize; - - uint16_t extendedFlags = 0; - if (extendedHeaderSize >= 6) { - extendedFlags = U16_AT(&mData[4]); - - if (extendedHeaderSize >= 10) { - size_t paddingSize = U32_AT(&mData[6]); - - if (mFirstFrameOffset + paddingSize > mSize) { - free(mData); - mData = NULL; - - return false; - } - - mSize -= paddingSize; - } - - if (extendedFlags & 0x8000) { - ALOGV("have crc"); - } - } - } else if (header.version_major == 4 && (header.flags & 0x40)) { - // Version 2.4 has an optional extended header, that's different - // from Version 2.3's... - - if (mSize < 4) { - free(mData); - mData = NULL; - - return false; - } - - size_t ext_size; - if (!ParseSyncsafeInteger(mData, &ext_size)) { - free(mData); - mData = NULL; - - return false; - } - - if (ext_size < 6 || ext_size > mSize) { - free(mData); - mData = NULL; - - return false; - } - - mFirstFrameOffset = ext_size; - } - - if (header.version_major == 2) { - mVersion = ID3_V2_2; - } else if (header.version_major == 3) { - mVersion = ID3_V2_3; - } else { - CHECK_EQ(header.version_major, 4); - mVersion = ID3_V2_4; - } - - return true; -} - -void ID3::removeUnsynchronization() { - for (size_t i = 0; i + 1 < mSize; ++i) { - if (mData[i] == 0xff && mData[i + 1] == 0x00) { - memmove(&mData[i + 1], &mData[i + 2], mSize - i - 2); - --mSize; - } - } -} - -static void WriteSyncsafeInteger(uint8_t *dst, size_t x) { - for (size_t i = 0; i < 4; ++i) { - dst[3 - i] = (x & 0x7f); - x >>= 7; - } -} - -bool ID3::removeUnsynchronizationV2_4(bool iTunesHack) { - size_t oldSize = mSize; - - size_t offset = 0; - while (offset + 10 <= mSize) { - if (!memcmp(&mData[offset], "\0\0\0\0", 4)) { - break; - } - - size_t dataSize; - if (iTunesHack) { - dataSize = U32_AT(&mData[offset + 4]); - } else if (!ParseSyncsafeInteger(&mData[offset + 4], &dataSize)) { - return false; - } - - if (offset + dataSize + 10 > mSize) { - return false; - } - - uint16_t flags = U16_AT(&mData[offset + 8]); - uint16_t prevFlags = flags; - - if (flags & 1) { - // Strip data length indicator - - memmove(&mData[offset + 10], &mData[offset + 14], mSize - offset - 14); - mSize -= 4; - dataSize -= 4; - - flags &= ~1; - } - - if (flags & 2) { - // This file has "unsynchronization", so we have to replace occurrences - // of 0xff 0x00 with just 0xff in order to get the real data. - - size_t readOffset = offset + 11; - size_t writeOffset = offset + 11; - for (size_t i = 0; i + 1 < dataSize; ++i) { - if (mData[readOffset - 1] == 0xff - && mData[readOffset] == 0x00) { - ++readOffset; - --mSize; - --dataSize; - } - mData[writeOffset++] = mData[readOffset++]; - } - // move the remaining data following this frame - memmove(&mData[writeOffset], &mData[readOffset], oldSize - readOffset); - - flags &= ~2; - } - - if (flags != prevFlags || iTunesHack) { - WriteSyncsafeInteger(&mData[offset + 4], dataSize); - mData[offset + 8] = flags >> 8; - mData[offset + 9] = flags & 0xff; - } - - offset += 10 + dataSize; - } - - memset(&mData[mSize], 0, oldSize - mSize); - - return true; -} - -ID3::Iterator::Iterator(const ID3 &parent, const char *id) - : mParent(parent), - mID(NULL), - mOffset(mParent.mFirstFrameOffset), - mFrameData(NULL), - mFrameSize(0) { - if (id) { - mID = strdup(id); - } - - findFrame(); -} - -ID3::Iterator::~Iterator() { - if (mID) { - free(mID); - mID = NULL; - } -} - -bool ID3::Iterator::done() const { - return mFrameData == NULL; -} - -void ID3::Iterator::next() { - if (mFrameData == NULL) { - return; - } - - mOffset += mFrameSize; - - findFrame(); -} - -void ID3::Iterator::getID(String8 *id) const { - id->setTo(""); - - if (mFrameData == NULL) { - return; - } - - if (mParent.mVersion == ID3_V2_2) { - id->setTo((const char *)&mParent.mData[mOffset], 3); - } else if (mParent.mVersion == ID3_V2_3 || mParent.mVersion == ID3_V2_4) { - id->setTo((const char *)&mParent.mData[mOffset], 4); - } else { - CHECK(mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1); - - switch (mOffset) { - case 3: - id->setTo("TT2"); - break; - case 33: - id->setTo("TP1"); - break; - case 63: - id->setTo("TAL"); - break; - case 93: - id->setTo("TYE"); - break; - case 97: - id->setTo("COM"); - break; - case 126: - id->setTo("TRK"); - break; - case 127: - id->setTo("TCO"); - break; - default: - CHECK(!"should not be here."); - break; - } - } -} - -static void convertISO8859ToString8( - const uint8_t *data, size_t size, - String8 *s) { - size_t utf8len = 0; - for (size_t i = 0; i < size; ++i) { - if (data[i] == '\0') { - size = i; - break; - } else if (data[i] < 0x80) { - ++utf8len; - } else { - utf8len += 2; - } - } - - if (utf8len == size) { - // Only ASCII characters present. - - s->setTo((const char *)data, size); - return; - } - - char *tmp = new char[utf8len]; - char *ptr = tmp; - for (size_t i = 0; i < size; ++i) { - if (data[i] == '\0') { - break; - } else if (data[i] < 0x80) { - *ptr++ = data[i]; - } else if (data[i] < 0xc0) { - *ptr++ = 0xc2; - *ptr++ = data[i]; - } else { - *ptr++ = 0xc3; - *ptr++ = data[i] - 64; - } - } - - s->setTo(tmp, utf8len); - - delete[] tmp; - tmp = NULL; -} - -// the 2nd argument is used to get the data following the \0 in a comment field -void ID3::Iterator::getString(String8 *id, String8 *comment) const { - getstring(id, false); - if (comment != NULL) { - getstring(comment, true); - } -} - -// comment fields (COM/COMM) contain an initial short descriptor, followed by \0, -// followed by more data. The data following the \0 can be retrieved by setting -// "otherdata" to true. -void ID3::Iterator::getstring(String8 *id, bool otherdata) const { - id->setTo(""); - - const uint8_t *frameData = mFrameData; - if (frameData == NULL) { - return; - } - - uint8_t encoding = *frameData; - - if (mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1) { - if (mOffset == 126 || mOffset == 127) { - // Special treatment for the track number and genre. - char tmp[16]; - sprintf(tmp, "%d", (int)*frameData); - - id->setTo(tmp); - return; - } - - convertISO8859ToString8(frameData, mFrameSize, id); - return; - } - - size_t n = mFrameSize - getHeaderLength() - 1; - if (otherdata) { - // skip past the encoding, language, and the 0 separator - frameData += 4; - int32_t i = n - 4; - while(--i >= 0 && *++frameData != 0) ; - int skipped = (frameData - mFrameData); - if (skipped >= (int)n) { - return; - } - n -= skipped; - } - - if (encoding == 0x00) { - // ISO 8859-1 - convertISO8859ToString8(frameData + 1, n, id); - } else if (encoding == 0x03) { - // UTF-8 - id->setTo((const char *)(frameData + 1), n); - } else if (encoding == 0x02) { - // UTF-16 BE, no byte order mark. - // API wants number of characters, not number of bytes... - int len = n / 2; - const char16_t *framedata = (const char16_t *) (frameData + 1); - char16_t *framedatacopy = NULL; -#if BYTE_ORDER == LITTLE_ENDIAN - framedatacopy = new char16_t[len]; - for (int i = 0; i < len; i++) { - framedatacopy[i] = bswap_16(framedata[i]); - } - framedata = framedatacopy; -#endif - id->setTo(framedata, len); - if (framedatacopy != NULL) { - delete[] framedatacopy; - } - } else { - // UCS-2 - // API wants number of characters, not number of bytes... - int len = n / 2; - const char16_t *framedata = (const char16_t *) (frameData + 1); - char16_t *framedatacopy = NULL; - if (*framedata == 0xfffe) { - // endianness marker doesn't match host endianness, convert - framedatacopy = new char16_t[len]; - for (int i = 0; i < len; i++) { - framedatacopy[i] = bswap_16(framedata[i]); - } - framedata = framedatacopy; - } - // If the string starts with an endianness marker, skip it - if (*framedata == 0xfeff) { - framedata++; - len--; - } - id->setTo(framedata, len); - if (framedatacopy != NULL) { - delete[] framedatacopy; - } - } -} - -const uint8_t *ID3::Iterator::getData(size_t *length) const { - *length = 0; - - if (mFrameData == NULL) { - return NULL; - } - - *length = mFrameSize - getHeaderLength(); - - return mFrameData; -} - -size_t ID3::Iterator::getHeaderLength() const { - if (mParent.mVersion == ID3_V2_2) { - return 6; - } else if (mParent.mVersion == ID3_V2_3 || mParent.mVersion == ID3_V2_4) { - return 10; - } else { - CHECK(mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1); - return 0; - } -} - -void ID3::Iterator::findFrame() { - for (;;) { - mFrameData = NULL; - mFrameSize = 0; - - if (mParent.mVersion == ID3_V2_2) { - if (mOffset + 6 > mParent.mSize) { - return; - } - - if (!memcmp(&mParent.mData[mOffset], "\0\0\0", 3)) { - return; - } - - mFrameSize = - (mParent.mData[mOffset + 3] << 16) - | (mParent.mData[mOffset + 4] << 8) - | mParent.mData[mOffset + 5]; - - mFrameSize += 6; - - if (mOffset + mFrameSize > mParent.mSize) { - ALOGV("partial frame at offset %d (size = %d, bytes-remaining = %d)", - mOffset, mFrameSize, mParent.mSize - mOffset - 6); - return; - } - - mFrameData = &mParent.mData[mOffset + 6]; - - if (!mID) { - break; - } - - char id[4]; - memcpy(id, &mParent.mData[mOffset], 3); - id[3] = '\0'; - - if (!strcmp(id, mID)) { - break; - } - } else if (mParent.mVersion == ID3_V2_3 - || mParent.mVersion == ID3_V2_4) { - if (mOffset + 10 > mParent.mSize) { - return; - } - - if (!memcmp(&mParent.mData[mOffset], "\0\0\0\0", 4)) { - return; - } - - size_t baseSize; - if (mParent.mVersion == ID3_V2_4) { - if (!ParseSyncsafeInteger( - &mParent.mData[mOffset + 4], &baseSize)) { - return; - } - } else { - baseSize = U32_AT(&mParent.mData[mOffset + 4]); - } - - mFrameSize = 10 + baseSize; - - if (mOffset + mFrameSize > mParent.mSize) { - ALOGV("partial frame at offset %d (size = %d, bytes-remaining = %d)", - mOffset, mFrameSize, mParent.mSize - mOffset - 10); - return; - } - - uint16_t flags = U16_AT(&mParent.mData[mOffset + 8]); - - if ((mParent.mVersion == ID3_V2_4 && (flags & 0x000c)) - || (mParent.mVersion == ID3_V2_3 && (flags & 0x00c0))) { - // Compression or encryption are not supported at this time. - // Per-frame unsynchronization and data-length indicator - // have already been taken care of. - - ALOGV("Skipping unsupported frame (compression, encryption " - "or per-frame unsynchronization flagged"); - - mOffset += mFrameSize; - continue; - } - - mFrameData = &mParent.mData[mOffset + 10]; - - if (!mID) { - break; - } - - char id[5]; - memcpy(id, &mParent.mData[mOffset], 4); - id[4] = '\0'; - - if (!strcmp(id, mID)) { - break; - } - } else { - CHECK(mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1); - - if (mOffset >= mParent.mSize) { - return; - } - - mFrameData = &mParent.mData[mOffset]; - - switch (mOffset) { - case 3: - case 33: - case 63: - mFrameSize = 30; - break; - case 93: - mFrameSize = 4; - break; - case 97: - if (mParent.mVersion == ID3_V1) { - mFrameSize = 30; - } else { - mFrameSize = 29; - } - break; - case 126: - mFrameSize = 1; - break; - case 127: - mFrameSize = 1; - break; - default: - CHECK(!"Should not be here, invalid offset."); - break; - } - - if (!mID) { - break; - } - - String8 id; - getID(&id); - - if (id == mID) { - break; - } - } - - mOffset += mFrameSize; - } -} - -static size_t StringSize(const uint8_t *start, uint8_t encoding) { - if (encoding == 0x00 || encoding == 0x03) { - // ISO 8859-1 or UTF-8 - return strlen((const char *)start) + 1; - } - - // UCS-2 - size_t n = 0; - while (start[n] != '\0' || start[n + 1] != '\0') { - n += 2; - } - - // Add size of null termination. - return n + 2; -} - -const void * -ID3::getAlbumArt(size_t *length, String8 *mime) const { - *length = 0; - mime->setTo(""); - - Iterator it( - *this, - (mVersion == ID3_V2_3 || mVersion == ID3_V2_4) ? "APIC" : "PIC"); - - while (!it.done()) { - size_t size; - const uint8_t *data = it.getData(&size); - - if (mVersion == ID3_V2_3 || mVersion == ID3_V2_4) { - uint8_t encoding = data[0]; - mime->setTo((const char *)&data[1]); - size_t mimeLen = strlen((const char *)&data[1]) + 1; - - uint8_t picType = data[1 + mimeLen]; -#if 0 - if (picType != 0x03) { - // Front Cover Art - it.next(); - continue; - } -#endif - - size_t descLen = StringSize(&data[2 + mimeLen], encoding); - - *length = size - 2 - mimeLen - descLen; - - return &data[2 + mimeLen + descLen]; - } else { - uint8_t encoding = data[0]; - - if (!memcmp(&data[1], "PNG", 3)) { - mime->setTo("image/png"); - } else if (!memcmp(&data[1], "JPG", 3)) { - mime->setTo("image/jpeg"); - } else if (!memcmp(&data[1], "-->", 3)) { - mime->setTo("text/plain"); - } else { - return NULL; - } - -#if 0 - uint8_t picType = data[4]; - if (picType != 0x03) { - // Front Cover Art - it.next(); - continue; - } -#endif - - size_t descLen = StringSize(&data[5], encoding); - - *length = size - 5 - descLen; - - return &data[5 + descLen]; - } - } - - return NULL; -} - -bool ID3::parseV1(const sp &source) { - const size_t V1_TAG_SIZE = 128; - - off64_t size; - if (source->getSize(&size) != OK || size < (off64_t)V1_TAG_SIZE) { - return false; - } - - mData = (uint8_t *)malloc(V1_TAG_SIZE); - if (source->readAt(size - V1_TAG_SIZE, mData, V1_TAG_SIZE) - != (ssize_t)V1_TAG_SIZE) { - free(mData); - mData = NULL; - - return false; - } - - if (memcmp("TAG", mData, 3)) { - free(mData); - mData = NULL; - - return false; - } - - mSize = V1_TAG_SIZE; - mFirstFrameOffset = 3; - - if (mData[V1_TAG_SIZE - 3] != 0) { - mVersion = ID3_V1; - } else { - mVersion = ID3_V1_1; - } - - return true; -} - -} // namespace stagefright - -#undef LOG_TAG diff --git a/media/libstagefright/frameworks/av/media/libstagefright/include/ID3.h b/media/libstagefright/frameworks/av/media/libstagefright/include/ID3.h deleted file mode 100644 index 27420e6a295a..000000000000 --- a/media/libstagefright/frameworks/av/media/libstagefright/include/ID3.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ID3_H_ - -#define ID3_H_ - -#include - -namespace stagefright { - -class DataSource; -class String8; - -struct ID3 { - enum Version { - ID3_UNKNOWN, - ID3_V1, - ID3_V1_1, - ID3_V2_2, - ID3_V2_3, - ID3_V2_4, - }; - - ID3(const sp &source, bool ignoreV1 = false); - ID3(const uint8_t *data, size_t size, bool ignoreV1 = false); - ~ID3(); - - bool isValid() const; - - Version version() const; - - const void *getAlbumArt(size_t *length, String8 *mime) const; - - struct Iterator { - Iterator(const ID3 &parent, const char *id); - ~Iterator(); - - bool done() const; - void getID(String8 *id) const; - void getString(String8 *s, String8 *ss = NULL) const; - const uint8_t *getData(size_t *length) const; - void next(); - - private: - const ID3 &mParent; - char *mID; - size_t mOffset; - - const uint8_t *mFrameData; - size_t mFrameSize; - - void findFrame(); - - size_t getHeaderLength() const; - void getstring(String8 *s, bool secondhalf) const; - - Iterator(const Iterator &); - Iterator &operator=(const Iterator &); - }; - - size_t rawSize() const { return mRawSize; } - -private: - bool mIsValid; - uint8_t *mData; - size_t mSize; - size_t mFirstFrameOffset; - Version mVersion; - - // size of the ID3 tag including header before any unsynchronization. - // only valid for IDV2+ - size_t mRawSize; - - bool parseV1(const sp &source); - bool parseV2(const sp &source); - void removeUnsynchronization(); - bool removeUnsynchronizationV2_4(bool iTunesHack); - - static bool ParseSyncsafeInteger(const uint8_t encoded[4], size_t *x); - - ID3(const ID3 &); - ID3 &operator=(const ID3 &); -}; - -} // namespace stagefright - -#endif // ID3_H_ - diff --git a/media/libstagefright/moz.build b/media/libstagefright/moz.build index 9b0f76af6099..1c934c014720 100644 --- a/media/libstagefright/moz.build +++ b/media/libstagefright/moz.build @@ -102,7 +102,6 @@ UNIFIED_SOURCES += [ 'frameworks/av/media/libstagefright/foundation/ABitReader.cpp', 'frameworks/av/media/libstagefright/foundation/ABuffer.cpp', 'frameworks/av/media/libstagefright/foundation/AString.cpp', - 'frameworks/av/media/libstagefright/id3/ID3.cpp', 'frameworks/av/media/libstagefright/MediaBuffer.cpp', 'frameworks/av/media/libstagefright/MediaDefs.cpp', 'frameworks/av/media/libstagefright/MediaSource.cpp', From e0ac6671b5533dbab73e6222e65495bd754019f8 Mon Sep 17 00:00:00 2001 From: Edgar Chen Date: Mon, 5 Oct 2015 19:11:52 +0800 Subject: [PATCH 162/228] Bug 1211407 - Make |mach mochitest| use the adb under `out/host/*/bin` if no --adbpath specified. r=ahal --HG-- extra : transplant_source : %E8%EF%D5%B0%BF%EA6%AA%A1Y%07%8C%DC%82%8B%D6%E0%FE%0F%21 --- testing/mochitest/mach_commands.py | 14 -------------- testing/mochitest/mochitest_options.py | 2 +- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/testing/mochitest/mach_commands.py b/testing/mochitest/mach_commands.py index ec8399b39cc5..819e38109f28 100644 --- a/testing/mochitest/mach_commands.py +++ b/testing/mochitest/mach_commands.py @@ -30,13 +30,6 @@ import mozpack.path as mozpath here = os.path.abspath(os.path.dirname(__file__)) -ADB_NOT_FOUND = ''' -The mochitest command requires the adb binary to be on your path. - -If you have a B2G build, this can be found in -'{}/out/host//bin'. -'''.lstrip() - GAIA_PROFILE_NOT_FOUND = ''' The mochitest command requires a non-debug gaia profile. Either pass in --profile, or set the GAIA_PROFILE environment variable. @@ -287,13 +280,6 @@ class MochitestRunner(MozbuildObject): if options.desktop: return mochitest.run_desktop_mochitests(options) - try: - which.which('adb') - except which.WhichError: - # TODO Find adb automatically if it isn't on the path - print(ADB_NOT_FOUND.format(options.b2gPath)) - return 1 - return mochitest.run_remote_mochitests(options) def run_desktop_test(self, context, tests=None, suite=None, **kwargs): diff --git a/testing/mochitest/mochitest_options.py b/testing/mochitest/mochitest_options.py index 60b3ea2b82a9..e12c0d212130 100644 --- a/testing/mochitest/mochitest_options.py +++ b/testing/mochitest/mochitest_options.py @@ -812,7 +812,7 @@ class B2GArguments(ArgumentContainer): }], [["--adbpath"], {"dest": "adbPath", - "default": "adb", + "default": None, "help": "Path to adb binary.", "suppress": True, }], From 02b6f298047e246b2151919830fa632b3de62836 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Pag=C3=A8s?= Date: Mon, 5 Oct 2015 21:29:37 +0200 Subject: [PATCH 163/228] Bug 1211608 - talos: error when trying to extract minidump from browser hang on windows. r=jmaher --HG-- extra : transplant_source : %92B%D9o%F4D%07%B27%C3%FCn%7B%60%BC%C0%E1%19%AFX --- testing/talos/talos/talos_process.py | 8 ++++++-- testing/talos/talos/ttest.py | 11 ++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/testing/talos/talos/talos_process.py b/testing/talos/talos/talos_process.py index 19e8c58257b6..584a915b601b 100644 --- a/testing/talos/talos/talos_process.py +++ b/testing/talos/talos/talos_process.py @@ -53,7 +53,8 @@ class Reader(object): self.output.append(line) -def run_browser(command, timeout=None, on_started=None, **kwargs): +def run_browser(command, minidump_dir, timeout=None, on_started=None, + **kwargs): """ Run the browser using the given `command`. @@ -64,6 +65,9 @@ def run_browser(command, timeout=None, on_started=None, **kwargs): the end. If this is not possible, an exception will be raised. :param command: the commad (as a string list) to run the browser + :param minidump_dir: a path where to extract minidumps in case the + browser hang. This have to be the same value + used in `mozcrash.check_for_crashes`. :param timeout: if specified, timeout to wait for the browser before we raise a :class:`TalosError` :param on_started: a callback that can be used to do things just after @@ -92,7 +96,7 @@ def run_browser(command, timeout=None, on_started=None, **kwargs): # or the browser just terminated - or we have a timeout if not event.wait(timeout): # try to extract the minidump stack if the browser hangs - mozcrash.kill_and_get_minidump(proc.pid) + mozcrash.kill_and_get_minidump(proc.pid, minidump_dir) raise TalosError("timeout") if reader.got_end_timestamp: for i in range(1, wait_for_quit_timeout): diff --git a/testing/talos/talos/ttest.py b/testing/talos/talos/ttest.py index b1f48d01567c..091298900e65 100644 --- a/testing/talos/talos/ttest.py +++ b/testing/talos/talos/ttest.py @@ -33,13 +33,12 @@ from talos.cmanager import CounterManagement class TTest(object): platform_type = utils.PLATFORM_TYPE - def check_for_crashes(self, browser_config, profile_dir, test_name): + def check_for_crashes(self, browser_config, minidump_dir, test_name): # check for minidumps - minidumpdir = os.path.join(profile_dir, 'minidumps') - found = mozcrash.check_for_crashes(minidumpdir, + found = mozcrash.check_for_crashes(minidump_dir, browser_config['symbols_path'], test_name=test_name) - mozfile.remove(minidumpdir) + mozfile.remove(minidump_dir) if found: raise TalosCrash("Found crashes after test run, terminating test") @@ -62,6 +61,7 @@ class TTest(object): return self._runTest(browser_config, test_config, setup) def _runTest(self, browser_config, test_config, setup): + minidump_dir = os.path.join(setup.profile_dir, 'minidumps') counters = test_config.get(self.platform_type + 'counters', []) resolution = test_config['resolution'] @@ -165,6 +165,7 @@ class TTest(object): try: pcontext = run_browser( command_args, + minidump_dir, timeout=timeout, env=setup.env, # start collecting counters as soon as possible @@ -235,7 +236,7 @@ class TTest(object): if setup.sps_profile: setup.sps_profile.symbolicate(i) - self.check_for_crashes(browser_config, setup.profile_dir, + self.check_for_crashes(browser_config, minidump_dir, test_config['name']) # include global (cross-cycle) counters From 8a586a51d43bfdc25b964de7f8593c7f6a5900a6 Mon Sep 17 00:00:00 2001 From: Nigel Babu Date: Wed, 7 Oct 2015 12:32:01 +0530 Subject: [PATCH 164/228] Backed out changeset 3a4fb0ededfd (bug 1198664) for B2G build bustage ON A CLOSED TREE --- dom/media/omx/MediaCodecProxy.cpp | 10 +- dom/media/omx/MediaCodecProxy.h | 2 +- .../gonk/GonkAudioDecoderManager.cpp | 7 +- .../platforms/gonk/GonkMediaDataDecoder.cpp | 238 ++++++++---------- .../platforms/gonk/GonkMediaDataDecoder.h | 79 +++--- .../gonk/GonkVideoDecoderManager.cpp | 6 +- 6 files changed, 147 insertions(+), 195 deletions(-) diff --git a/dom/media/omx/MediaCodecProxy.cpp b/dom/media/omx/MediaCodecProxy.cpp index 5c0eec575e74..5e53c258a96d 100644 --- a/dom/media/omx/MediaCodecProxy.cpp +++ b/dom/media/omx/MediaCodecProxy.cpp @@ -14,6 +14,7 @@ #include #define MCP_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "MediaCodecProxy", __VA_ARGS__) +#define TIMEOUT_DEQUEUE_INPUTBUFFER_MS 1000000ll namespace android { @@ -570,8 +571,7 @@ bool MediaCodecProxy::UpdateOutputBuffers() } status_t MediaCodecProxy::Input(const uint8_t* aData, uint32_t aDataSize, - int64_t aTimestampUsecs, uint64_t aflags, - int64_t aTimeoutUs) + int64_t aTimestampUsecs, uint64_t aflags) { // Read Lock for mCodec { @@ -583,11 +583,9 @@ status_t MediaCodecProxy::Input(const uint8_t* aData, uint32_t aDataSize, } size_t index; - status_t err = dequeueInputBuffer(&index, aTimeoutUs); + status_t err = dequeueInputBuffer(&index, TIMEOUT_DEQUEUE_INPUTBUFFER_MS); if (err != OK) { - if (err != -EAGAIN) { - MCP_LOG("dequeueInputBuffer returned %d", err); - } + MCP_LOG("dequeueInputBuffer returned %d", err); return err; } diff --git a/dom/media/omx/MediaCodecProxy.h b/dom/media/omx/MediaCodecProxy.h index b21639c20d57..890c004128b0 100644 --- a/dom/media/omx/MediaCodecProxy.h +++ b/dom/media/omx/MediaCodecProxy.h @@ -129,7 +129,7 @@ public: // If aData is null, will notify decoder input EOS status_t Input(const uint8_t* aData, uint32_t aDataSize, - int64_t aTimestampUsecs, uint64_t flags, int64_t aTimeoutUs = 0); + int64_t aTimestampUsecs, uint64_t flags); status_t Output(MediaBuffer** aBuffer, int64_t aTimeoutUs); bool Prepare(); void ReleaseMediaResources(); diff --git a/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp b/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp index 131b7206fe15..377c47a8d6a7 100644 --- a/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp +++ b/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp @@ -21,14 +21,12 @@ #include "MediaData.h" #include "MediaInfo.h" -#define CODECCONFIG_TIMEOUT_US 10000LL -#define READ_OUTPUT_BUFFER_TIMEOUT_US 0LL - #include #define GADM_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "GonkAudioDecoderManager", __VA_ARGS__) extern PRLogModuleInfo* GetPDMLog(); #define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__)) +#define READ_OUTPUT_BUFFER_TIMEOUT_US 3000 using namespace android; typedef android::MediaCodecProxy MediaCodecProxy; @@ -94,8 +92,7 @@ GonkAudioDecoderManager::InitMediaCodecProxy() if (mMimeType.EqualsLiteral("audio/mp4a-latm")) { rv = mDecoder->Input(mCodecSpecificData->Elements(), mCodecSpecificData->Length(), 0, - android::MediaCodec::BUFFER_FLAG_CODECCONFIG, - CODECCONFIG_TIMEOUT_US); + android::MediaCodec::BUFFER_FLAG_CODECCONFIG); } if (rv == OK) { diff --git a/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp b/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp index 39fbacbfa4d2..e16c5de06342 100644 --- a/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp +++ b/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp @@ -13,8 +13,6 @@ #include "mozilla/Logging.h" #include #define GMDD_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "GonkMediaDataDecoder", __VA_ARGS__) -#define INPUT_TIMEOUT_US 0LL // Don't wait for buffer if none is available. -#define MIN_QUEUED_SAMPLES 2 extern PRLogModuleInfo* GetPDMLog(); #define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__)) @@ -47,53 +45,40 @@ GonkDecoderManager::InitLoopers(MediaData::Type aType) nsresult GonkDecoderManager::Input(MediaRawData* aSample) { + MutexAutoLock lock(mMutex); nsRefPtr sample; - if (aSample) { - sample = aSample; - } else { + if (!aSample) { // It means EOS with empty sample. sample = new MediaRawData(); - } - { - MutexAutoLock lock(mMutex); - mQueuedSamples.AppendElement(sample); + } else { + sample = aSample; } - sp input = new AMessage(kNotifyProcessInput, id()); - if (!aSample) { - input->setInt32("input-eos", 1); - } - input->post(); - return NS_OK; -} + mQueuedSamples.AppendElement(sample); -int32_t -GonkDecoderManager::ProcessQueuedSample() -{ - MutexAutoLock lock(mMutex); status_t rv; while (mQueuedSamples.Length()) { nsRefPtr data = mQueuedSamples.ElementAt(0); { + MutexAutoUnlock unlock(mMutex); rv = mDecoder->Input(reinterpret_cast(data->Data()), data->Size(), data->mTime, - 0, - INPUT_TIMEOUT_US); + 0); } if (rv == OK) { mQueuedSamples.RemoveElementAt(0); - mWaitOutput.AppendElement(data->mOffset); } else if (rv == -EAGAIN || rv == -ETIMEDOUT) { // In most cases, EAGAIN or ETIMEOUT are safe because OMX can't fill // buffer on time. - break; + return NS_OK; } else { - return rv; + return NS_ERROR_UNEXPECTED; } } - return mQueuedSamples.Length(); + + return NS_OK; } nsresult @@ -110,13 +95,10 @@ GonkDecoderManager::Flush() mLastTime = 0; - MonitorAutoLock lock(mFlushMonitor); - mIsFlushing = true; - sp flush = new AMessage(kNotifyProcessFlush, id()); - flush->post(); - while (mIsFlushing) { - lock.Wait(); + if (mDecoder->flush() != OK) { + return NS_ERROR_FAILURE; } + return NS_OK; } @@ -141,112 +123,10 @@ GonkDecoderManager::HasQueuedSample() return mQueuedSamples.Length(); } -void -GonkDecoderManager::ProcessInput(bool aEndOfStream) -{ - status_t rv = ProcessQueuedSamples(); - if (rv >= 0) { - if (!aEndOfStream && rv <= MIN_QUEUED_SAMPLES) { - mDecodeCallback->InputExhausted(); - } - - if (mToDo.get() == nullptr) { - mToDo = new AMessage(kNotifyDecoderActivity, id()); - if (aEndOfStream) { - mToDo->setInt32("input-eos", 1); - } - mDecoder->requestActivityNotification(mToDo); - } - } else { - GMDD_LOG("input processed: error#%d", rv); - mDecodeCallback->Error(); - } -} - -void -GonkDecoderManager::ProcessFlush() -{ - MonitorAutoLock lock(mFlushMonitor); - mWaitOutput.Clear(); - if (mDecoder->flush() != OK) { - GMDD_LOG("flush error"); - mDecodeCallback->Error(); - } - mIsFlushing = false; - lock.NotifyAll(); -} - -void -GonkDecoderManager::ProcessToDo(bool aEndOfStream) -{ - MOZ_ASSERT(mToDo.get() != nullptr); - mToDo.clear(); - - if (HasQueuedSample()) { - status_t pendingInput = ProcessQueuedSamples(); - if (pendingInput < 0) { - mDecodeCallback->Error(); - return; - } - if (!aEndOfStream && pendingInput <= MIN_QUEUED_SAMPLES) { - mDecodeCallback->InputExhausted(); - } - } - - nsresult rv = NS_OK; - while (mWaitOutput.Length() > 0) { - nsRefPtr output; - int64_t offset = mWaitOutput.ElementAt(0); - rv = Output(offset, output); - if (rv == NS_OK) { - mWaitOutput.RemoveElementAt(0); - mDecodeCallback->Output(output); - } else if (rv == NS_ERROR_ABORT) { - GMDD_LOG("eos output"); - mWaitOutput.RemoveElementAt(0); - MOZ_ASSERT(mQueuedSamples.IsEmpty()); - MOZ_ASSERT(mWaitOutput.IsEmpty()); - // EOS - if (output) { - mDecodeCallback->Output(output); - } - mDecodeCallback->DrainComplete(); - return; - } else if (rv == NS_ERROR_NOT_AVAILABLE) { - break; - } else { - mDecodeCallback->Error(); - return; - } - } - - if (HasQueuedSample() || mWaitOutput.Length() > 0) { - mToDo = new AMessage(kNotifyDecoderActivity, id()); - mDecoder->requestActivityNotification(mToDo); - } -} - void GonkDecoderManager::onMessageReceived(const sp &aMessage) { switch (aMessage->what()) { - case kNotifyProcessInput: - { - int32_t eos = 0; - ProcessInput(aMessage->findInt32("input-eos", &eos) && eos); - break; - } - case kNotifyProcessFlush: - { - ProcessFlush(); - break; - } - case kNotifyDecoderActivity: - { - int32_t eos = 0; - ProcessToDo(aMessage->findInt32("input-eos", &eos) && eos); - break; - } default: { TRESPASS(); @@ -259,7 +139,10 @@ GonkMediaDataDecoder::GonkMediaDataDecoder(GonkDecoderManager* aManager, FlushableTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback) : mTaskQueue(aTaskQueue) + , mCallback(aCallback) , mManager(aManager) + , mSignaledEOS(false) + , mDrainComplete(false) { MOZ_COUNT_CTOR(GonkMediaDataDecoder); mManager->SetDecodeCallback(aCallback); @@ -273,6 +156,8 @@ GonkMediaDataDecoder::~GonkMediaDataDecoder() nsRefPtr GonkMediaDataDecoder::Init() { + mDrainComplete = false; + return mManager->Init(); } @@ -291,10 +176,79 @@ GonkMediaDataDecoder::Shutdown() nsresult GonkMediaDataDecoder::Input(MediaRawData* aSample) { - mManager->Input(aSample); + nsCOMPtr runnable( + NS_NewRunnableMethodWithArg>( + this, + &GonkMediaDataDecoder::ProcessDecode, + nsRefPtr(aSample))); + mTaskQueue->Dispatch(runnable.forget()); return NS_OK; } +void +GonkMediaDataDecoder::ProcessDecode(MediaRawData* aSample) +{ + nsresult rv = mManager->Input(aSample); + if (rv != NS_OK) { + NS_WARNING("GonkMediaDataDecoder failed to input data"); + GMDD_LOG("Failed to input data err: %d",int(rv)); + mCallback->Error(); + return; + } + if (aSample) { + mLastStreamOffset = aSample->mOffset; + } + ProcessOutput(); +} + +void +GonkMediaDataDecoder::ProcessOutput() +{ + nsRefPtr output; + nsresult rv = NS_ERROR_ABORT; + + while (!mDrainComplete) { + // There are samples in queue, try to send them into decoder when EOS. + if (mSignaledEOS && mManager->HasQueuedSample()) { + GMDD_LOG("ProcessOutput: drain all input samples"); + rv = mManager->Input(nullptr); + } + rv = mManager->Output(mLastStreamOffset, output); + if (rv == NS_OK) { + mCallback->Output(output); + continue; + } else if (rv == NS_ERROR_NOT_AVAILABLE && mSignaledEOS) { + // Try to get more frames before getting EOS frame + continue; + } + else { + break; + } + } + + if (rv == NS_ERROR_NOT_AVAILABLE && !mSignaledEOS) { + mCallback->InputExhausted(); + return; + } + if (rv != NS_OK) { + NS_WARNING("GonkMediaDataDecoder failed to output data"); + GMDD_LOG("Failed to output data"); + // GonkDecoderManangers report NS_ERROR_ABORT when EOS is reached. + if (rv == NS_ERROR_ABORT) { + if (output) { + mCallback->Output(output); + } + mCallback->DrainComplete(); + MOZ_ASSERT_IF(mSignaledEOS, !mManager->HasQueuedSample()); + mSignaledEOS = false; + mDrainComplete = true; + return; + } + GMDD_LOG("Callback error!"); + mCallback->Error(); + } +} + nsresult GonkMediaDataDecoder::Flush() { @@ -303,13 +257,25 @@ GonkMediaDataDecoder::Flush() // it's executing at all. Note the MP4Reader ignores all output while // flushing. mTaskQueue->Flush(); + mDrainComplete = false; return mManager->Flush(); } +void +GonkMediaDataDecoder::ProcessDrain() +{ + // Notify decoder input EOS by sending a null data. + ProcessDecode(nullptr); + mSignaledEOS = true; + ProcessOutput(); +} + nsresult GonkMediaDataDecoder::Drain() { - mManager->Input(nullptr); + nsCOMPtr runnable = + NS_NewRunnableMethod(this, &GonkMediaDataDecoder::ProcessDrain); + mTaskQueue->Dispatch(runnable.forget()); return NS_OK; } diff --git a/dom/media/platforms/gonk/GonkMediaDataDecoder.h b/dom/media/platforms/gonk/GonkMediaDataDecoder.h index 282dafbe631c..a327fca97887 100644 --- a/dom/media/platforms/gonk/GonkMediaDataDecoder.h +++ b/dom/media/platforms/gonk/GonkMediaDataDecoder.h @@ -26,12 +26,19 @@ public: virtual ~GonkDecoderManager() {} - virtual nsRefPtr Init() = 0; - - // Asynchronously send sample into mDecoder. If out of input buffer, aSample - // will be queued for later re-send. + // Add samples into OMX decoder or queue them if decoder is out of input buffer. nsresult Input(MediaRawData* aSample); + // Produces decoded output, it blocks until output can be produced or a timeout + // is expired or until EOS. Returns NS_OK on success, or NS_ERROR_NOT_AVAILABLE + // if there's not enough data to produce more output. If this returns a failure + // code other than NS_ERROR_NOT_AVAILABLE, an error will be reported to the + // MP4Reader. + // The overrided class should follow the same behaviour. + virtual nsresult Output(int64_t aStreamOffset, + nsRefPtr& aOutput) = 0; + virtual nsRefPtr Init() = 0; + // Flush the queued sample. nsresult Flush(); @@ -52,8 +59,6 @@ protected: GonkDecoderManager() : mMutex("GonkDecoderManager") , mLastTime(0) - , mFlushMonitor("GonkDecoderManager::Flush") - , mIsFlushing(false) , mDecodeCallback(nullptr) {} @@ -61,21 +66,6 @@ protected: void onMessageReceived(const android::sp &aMessage) override; - // Produces decoded output. It returns NS_OK on success, or NS_ERROR_NOT_AVAILABLE - // when output is not produced yet. - // If this returns a failure code other than NS_ERROR_NOT_AVAILABLE, an error - // will be reported through mDecodeCallback. - virtual nsresult Output(int64_t aStreamOffset, - nsRefPtr& aOutput) = 0; - - // Send queued samples to OMX. It returns how many samples are still in - // queue after processing, or negtive error code if failed. - int32_t ProcessQueuedSamples(); - - void ProcessInput(bool aEndOfStream); - void ProcessFlush(); - void ProcessToDo(bool aEndOfStream); - nsRefPtr mCodecSpecificData; nsAutoCString mMimeType; @@ -84,18 +74,8 @@ protected: android::sp mDecoder; // Looper for mDecoder to run on. android::sp mDecodeLooper; - // Looper to run decode tasks such as processing input, output, flush, and - // recycling output buffers. + // Looper to run decode tasks such as recycling output buffers. android::sp mTaskLooper; - enum { - // Decoder will send this to indicate internal state change such as input or - // output buffers availability. Used to run pending input & output tasks. - kNotifyDecoderActivity = 'nda ', - // Signal the decoder to flush. - kNotifyProcessFlush = 'npf ', - // Used to process queued samples when there is new input. - kNotifyProcessInput = 'npi ', - }; MozPromiseHolder mInitPromise; @@ -107,17 +87,6 @@ protected: int64_t mLastTime; // The last decoded frame presentation time. - Monitor mFlushMonitor; // Waits for flushing to complete. - bool mIsFlushing; - - // Remembers the notification that is currently waiting for the decoder event - // to avoid requesting more than one notification at the time, which is - // forbidden by mDecoder. - android::sp mToDo; - - // Stores the offset of every output that needs to be read from mDecoder. - nsTArray mWaitOutput; - MediaDataDecoderCallback* mDecodeCallback; // Reports decoder output or error. }; @@ -145,9 +114,33 @@ public: nsresult Shutdown() override; private: + + // Called on the task queue. Inserts the sample into the decoder, and + // extracts output if available, if aSample is null, it means there is + // no data from source, it will notify the decoder EOS and flush all the + // decoded frames. + void ProcessDecode(MediaRawData* aSample); + + // Called on the task queue. Extracts output if available, and delivers + // it to the reader. Called after ProcessDecode() and ProcessDrain(). + void ProcessOutput(); + + // Called on the task queue. Orders the Gonk to drain, and then extracts + // all available output. + void ProcessDrain(); + RefPtr mTaskQueue; + MediaDataDecoderCallback* mCallback; android::sp mManager; + + // The last offset into the media resource that was passed into Input(). + // This is used to approximate the decoder's position in the media resource. + int64_t mLastStreamOffset; + // Set it ture when there is no input data + bool mSignaledEOS; + // Set if there is no more output data from decoder + bool mDrainComplete; }; } // namespace mozilla diff --git a/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp b/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp index 6ea7518b6ea7..b62a0cdd7ff4 100644 --- a/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp +++ b/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp @@ -24,8 +24,7 @@ #include "mozilla/layers/TextureClient.h" #include -#define CODECCONFIG_TIMEOUT_US 10000LL -#define READ_OUTPUT_BUFFER_TIMEOUT_US 0LL +#define READ_OUTPUT_BUFFER_TIMEOUT_US 3000 #include #define GVDM_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "GonkVideoDecoderManager", __VA_ARGS__) @@ -417,8 +416,7 @@ GonkVideoDecoderManager::codecReserved() if (mMimeType.EqualsLiteral("video/mp4v-es")) { rv = mDecoder->Input(mCodecSpecificData->Elements(), mCodecSpecificData->Length(), 0, - android::MediaCodec::BUFFER_FLAG_CODECCONFIG, - CODECCONFIG_TIMEOUT_US); + android::MediaCodec::BUFFER_FLAG_CODECCONFIG); } if (rv != OK) { From 7e537c990931734799c33c6f2fed629c98aab02f Mon Sep 17 00:00:00 2001 From: Nigel Babu Date: Wed, 7 Oct 2015 12:33:08 +0530 Subject: [PATCH 165/228] Backed out changeset abaadd5361ad (bug 1198664) for B2G build bustage ON A CLOSED TREE --- .../gonk/GonkAudioDecoderManager.cpp | 86 ++++++++++-- .../platforms/gonk/GonkAudioDecoderManager.h | 25 +++- .../platforms/gonk/GonkMediaDataDecoder.cpp | 105 +-------------- .../platforms/gonk/GonkMediaDataDecoder.h | 45 +------ .../gonk/GonkVideoDecoderManager.cpp | 123 ++++++++++++++++-- .../platforms/gonk/GonkVideoDecoderManager.h | 47 ++++++- 6 files changed, 261 insertions(+), 170 deletions(-) diff --git a/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp b/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp index 377c47a8d6a7..d964b2625203 100644 --- a/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp +++ b/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp @@ -34,15 +34,18 @@ typedef android::MediaCodecProxy MediaCodecProxy; namespace mozilla { GonkAudioDecoderManager::GonkAudioDecoderManager(const AudioInfo& aConfig) - : mAudioChannels(aConfig.mChannels) + : mLastDecodedTime(0) + , mAudioChannels(aConfig.mChannels) , mAudioRate(aConfig.mRate) , mAudioProfile(aConfig.mProfile) , mAudioBuffer(nullptr) + , mMonitor("GonkAudioDecoderManager") { MOZ_COUNT_CTOR(GonkAudioDecoderManager); MOZ_ASSERT(mAudioChannels); mCodecSpecificData = aConfig.mCodecSpecificConfig; mMimeType = aConfig.mMimeType; + } GonkAudioDecoderManager::~GonkAudioDecoderManager() @@ -51,9 +54,9 @@ GonkAudioDecoderManager::~GonkAudioDecoderManager() } nsRefPtr -GonkAudioDecoderManager::Init() +GonkAudioDecoderManager::Init(MediaDataDecoderCallback* aCallback) { - if (InitMediaCodecProxy()) { + if (InitMediaCodecProxy(aCallback)) { return InitPromise::CreateAndResolve(TrackType::kAudioTrack, __func__); } else { return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__); @@ -61,14 +64,18 @@ GonkAudioDecoderManager::Init() } bool -GonkAudioDecoderManager::InitMediaCodecProxy() +GonkAudioDecoderManager::InitMediaCodecProxy(MediaDataDecoderCallback* aCallback) { status_t rv = OK; - if (!InitLoopers(MediaData::AUDIO_DATA)) { + if (mLooper != nullptr) { return false; } + // Create ALooper + mLooper = new ALooper; + mLooper->setName("GonkAudioDecoderManager"); + mLooper->start(); - mDecoder = MediaCodecProxy::CreateByType(mDecodeLooper, mMimeType.get(), false, nullptr); + mDecoder = MediaCodecProxy::CreateByType(mLooper, mMimeType.get(), false, nullptr); if (!mDecoder.get()) { return false; } @@ -103,6 +110,52 @@ GonkAudioDecoderManager::InitMediaCodecProxy() } } +bool +GonkAudioDecoderManager::HasQueuedSample() +{ + MonitorAutoLock mon(mMonitor); + return mQueueSample.Length(); +} + +nsresult +GonkAudioDecoderManager::Input(MediaRawData* aSample) +{ + MonitorAutoLock mon(mMonitor); + nsRefPtr sample; + + if (aSample) { + sample = aSample; + } else { + // It means EOS with empty sample. + sample = new MediaRawData(); + } + + mQueueSample.AppendElement(sample); + + status_t rv; + while (mQueueSample.Length()) { + nsRefPtr data = mQueueSample.ElementAt(0); + { + MonitorAutoUnlock mon_exit(mMonitor); + rv = mDecoder->Input(reinterpret_cast(data->Data()), + data->Size(), + data->mTime, + 0); + } + if (rv == OK) { + mQueueSample.RemoveElementAt(0); + } else if (rv == -EAGAIN || rv == -ETIMEDOUT) { + // In most cases, EAGAIN or ETIMEOUT are safe because OMX can't fill + // buffer on time. + return NS_OK; + } else { + return NS_ERROR_UNEXPECTED; + } + } + + return NS_OK; +} + nsresult GonkAudioDecoderManager::CreateAudioData(int64_t aStreamOffset, AudioData **v) { if (!(mAudioBuffer != nullptr && mAudioBuffer->data() != nullptr)) { @@ -122,13 +175,13 @@ GonkAudioDecoderManager::CreateAudioData(int64_t aStreamOffset, AudioData **v) { return NS_ERROR_NOT_AVAILABLE; } - if (mLastTime > timeUs) { + if (mLastDecodedTime > timeUs) { ReleaseAudioBuffer(); GADM_LOG("Output decoded sample time is revert. time=%lld", timeUs); MOZ_ASSERT(false); return NS_ERROR_NOT_AVAILABLE; } - mLastTime = timeUs; + mLastDecodedTime = timeUs; const uint8_t *data = static_cast(mAudioBuffer->data()); size_t dataOffset = mAudioBuffer->range_offset(); @@ -154,6 +207,23 @@ GonkAudioDecoderManager::CreateAudioData(int64_t aStreamOffset, AudioData **v) { return NS_OK; } +nsresult +GonkAudioDecoderManager::Flush() +{ + { + MonitorAutoLock mon(mMonitor); + mQueueSample.Clear(); + } + + mLastDecodedTime = 0; + + if (mDecoder->flush() != OK) { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + nsresult GonkAudioDecoderManager::Output(int64_t aStreamOffset, nsRefPtr& aOutData) diff --git a/dom/media/platforms/gonk/GonkAudioDecoderManager.h b/dom/media/platforms/gonk/GonkAudioDecoderManager.h index 473b03c31057..4fc70f61e58f 100644 --- a/dom/media/platforms/gonk/GonkAudioDecoderManager.h +++ b/dom/media/platforms/gonk/GonkAudioDecoderManager.h @@ -13,6 +13,7 @@ using namespace android; namespace android { +struct MOZ_EXPORT ALooper; class MOZ_EXPORT MediaBuffer; } // namespace android @@ -23,26 +24,44 @@ typedef android::MediaCodecProxy MediaCodecProxy; public: GonkAudioDecoderManager(const AudioInfo& aConfig); - virtual ~GonkAudioDecoderManager(); + virtual ~GonkAudioDecoderManager() override; - nsRefPtr Init() override; + nsRefPtr Init(MediaDataDecoderCallback* aCallback) override; + + nsresult Input(MediaRawData* aSample) override; nsresult Output(int64_t aStreamOffset, nsRefPtr& aOutput) override; + nsresult Flush() override; + + bool HasQueuedSample() override; + private: - bool InitMediaCodecProxy(); + bool InitMediaCodecProxy(MediaDataDecoderCallback* aCallback); nsresult CreateAudioData(int64_t aStreamOffset, AudioData** aOutData); void ReleaseAudioBuffer(); + int64_t mLastDecodedTime; + uint32_t mAudioChannels; uint32_t mAudioRate; const uint32_t mAudioProfile; + MediaDataDecoderCallback* mReaderCallback; android::MediaBuffer* mAudioBuffer; + android::sp mLooper; + + // This monitor protects mQueueSample. + Monitor mMonitor; + + // An queue with the MP4 samples which are waiting to be sent into OMX. + // If an element is an empty MP4Sample, that menas EOS. There should not + // any sample be queued after EOS. + nsTArray> mQueueSample; }; } // namespace mozilla diff --git a/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp b/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp index e16c5de06342..40153625dcb6 100644 --- a/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp +++ b/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp @@ -8,8 +8,6 @@ #include "nsTArray.h" #include "MediaCodecProxy.h" -#include - #include "mozilla/Logging.h" #include #define GMDD_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "GonkMediaDataDecoder", __VA_ARGS__) @@ -21,87 +19,6 @@ using namespace android; namespace mozilla { -bool -GonkDecoderManager::InitLoopers(MediaData::Type aType) -{ - MOZ_ASSERT(mDecodeLooper.get() == nullptr && mTaskLooper.get() == nullptr); - MOZ_ASSERT(aType == MediaData::VIDEO_DATA || aType == MediaData::AUDIO_DATA); - - const char* suffix = (aType == MediaData::VIDEO_DATA ? "video" : "audio"); - mDecodeLooper = new ALooper; - android::AString name("MediaCodecProxy/"); - name.append(suffix); - mDecodeLooper->setName(name.c_str()); - - mTaskLooper = new ALooper; - name.setTo("GonkDecoderManager/"); - name.append(suffix); - mTaskLooper->setName(name.c_str()); - mTaskLooper->registerHandler(this); - - return mDecodeLooper->start() == OK && mTaskLooper->start() == OK; -} - -nsresult -GonkDecoderManager::Input(MediaRawData* aSample) -{ - MutexAutoLock lock(mMutex); - nsRefPtr sample; - - if (!aSample) { - // It means EOS with empty sample. - sample = new MediaRawData(); - } else { - sample = aSample; - } - - mQueuedSamples.AppendElement(sample); - - status_t rv; - while (mQueuedSamples.Length()) { - nsRefPtr data = mQueuedSamples.ElementAt(0); - { - MutexAutoUnlock unlock(mMutex); - rv = mDecoder->Input(reinterpret_cast(data->Data()), - data->Size(), - data->mTime, - 0); - } - if (rv == OK) { - mQueuedSamples.RemoveElementAt(0); - } else if (rv == -EAGAIN || rv == -ETIMEDOUT) { - // In most cases, EAGAIN or ETIMEOUT are safe because OMX can't fill - // buffer on time. - return NS_OK; - } else { - return NS_ERROR_UNEXPECTED; - } - } - - return NS_OK; -} - -nsresult -GonkDecoderManager::Flush() -{ - if (mDecoder == nullptr) { - GMDD_LOG("Decoder is not initialized"); - return NS_ERROR_UNEXPECTED; - } - { - MutexAutoLock lock(mMutex); - mQueuedSamples.Clear(); - } - - mLastTime = 0; - - if (mDecoder->flush() != OK) { - return NS_ERROR_FAILURE; - } - - return NS_OK; -} - nsresult GonkDecoderManager::Shutdown() { @@ -116,25 +33,6 @@ GonkDecoderManager::Shutdown() return NS_OK; } -bool -GonkDecoderManager::HasQueuedSample() -{ - MutexAutoLock lock(mMutex); - return mQueuedSamples.Length(); -} - -void -GonkDecoderManager::onMessageReceived(const sp &aMessage) -{ - switch (aMessage->what()) { - default: - { - TRESPASS(); - break; - } - } -} - GonkMediaDataDecoder::GonkMediaDataDecoder(GonkDecoderManager* aManager, FlushableTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback) @@ -145,7 +43,6 @@ GonkMediaDataDecoder::GonkMediaDataDecoder(GonkDecoderManager* aManager, , mDrainComplete(false) { MOZ_COUNT_CTOR(GonkMediaDataDecoder); - mManager->SetDecodeCallback(aCallback); } GonkMediaDataDecoder::~GonkMediaDataDecoder() @@ -158,7 +55,7 @@ GonkMediaDataDecoder::Init() { mDrainComplete = false; - return mManager->Init(); + return mManager->Init(mCallback); } nsresult diff --git a/dom/media/platforms/gonk/GonkMediaDataDecoder.h b/dom/media/platforms/gonk/GonkMediaDataDecoder.h index a327fca97887..69d5a55b2114 100644 --- a/dom/media/platforms/gonk/GonkMediaDataDecoder.h +++ b/dom/media/platforms/gonk/GonkMediaDataDecoder.h @@ -7,10 +7,8 @@ #if !defined(GonkMediaDataDecoder_h_) #define GonkMediaDataDecoder_h_ #include "PlatformDecoderModule.h" -#include namespace android { -struct ALooper; class MediaCodecProxy; } // namespace android @@ -18,7 +16,7 @@ namespace mozilla { class MediaRawData; // Manage the data flow from inputting encoded data and outputting decode data. -class GonkDecoderManager : public android::AHandler { +class GonkDecoderManager { public: typedef TrackInfo::TrackType TrackType; typedef MediaDataDecoder::InitPromise InitPromise; @@ -26,8 +24,10 @@ public: virtual ~GonkDecoderManager() {} + virtual nsRefPtr Init(MediaDataDecoderCallback* aCallback) = 0; + // Add samples into OMX decoder or queue them if decoder is out of input buffer. - nsresult Input(MediaRawData* aSample); + virtual nsresult Input(MediaRawData* aSample) = 0; // Produces decoded output, it blocks until output can be produced or a timeout // is expired or until EOS. Returns NS_OK on success, or NS_ERROR_NOT_AVAILABLE @@ -37,57 +37,26 @@ public: // The overrided class should follow the same behaviour. virtual nsresult Output(int64_t aStreamOffset, nsRefPtr& aOutput) = 0; - virtual nsRefPtr Init() = 0; // Flush the queued sample. - nsresult Flush(); + virtual nsresult Flush() = 0; // Shutdown decoder and rejects the init promise. nsresult Shutdown(); // True if sample is queued. - bool HasQueuedSample(); - - // Set callback for decoder events, such as requesting more input, - // returning output, or reporting error. - void SetDecodeCallback(MediaDataDecoderCallback* aCallback) - { - mDecodeCallback = aCallback; - } + virtual bool HasQueuedSample() = 0; protected: - GonkDecoderManager() - : mMutex("GonkDecoderManager") - , mLastTime(0) - , mDecodeCallback(nullptr) - {} - - bool InitLoopers(MediaData::Type aType); - - void onMessageReceived(const android::sp &aMessage) override; - nsRefPtr mCodecSpecificData; nsAutoCString mMimeType; // MediaCodedc's wrapper that performs the decoding. android::sp mDecoder; - // Looper for mDecoder to run on. - android::sp mDecodeLooper; - // Looper to run decode tasks such as recycling output buffers. - android::sp mTaskLooper; MozPromiseHolder mInitPromise; - Mutex mMutex; // Protects mQueuedSamples. - // A queue that stores the samples waiting to be sent to mDecoder. - // Empty element means EOS and there shouldn't be any sample be queued after it. - // Samples are queued in caller's thread and dequeued in mTaskLooper. - nsTArray> mQueuedSamples; - - int64_t mLastTime; // The last decoded frame presentation time. - - MediaDataDecoderCallback* mDecodeCallback; // Reports decoder output or error. }; // Samples are decoded using the GonkDecoder (MediaCodec) @@ -132,7 +101,7 @@ private: RefPtr mTaskQueue; MediaDataDecoderCallback* mCallback; - android::sp mManager; + nsAutoPtr mManager; // The last offset into the media resource that was passed into Input(). // This is used to approximate the decoder's position in the media resource. diff --git a/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp b/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp index b62a0cdd7ff4..474bf5b0a074 100644 --- a/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp +++ b/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp @@ -17,7 +17,10 @@ #include "stagefright/MediaBuffer.h" #include "stagefright/MetaData.h" #include "stagefright/MediaErrors.h" +#include +#include #include +#include #include "GonkNativeWindow.h" #include "GonkNativeWindowClient.h" #include "mozilla/layers/GrallocTextureClient.h" @@ -41,9 +44,12 @@ GonkVideoDecoderManager::GonkVideoDecoderManager( mozilla::layers::ImageContainer* aImageContainer, const VideoInfo& aConfig) : mImageContainer(aImageContainer) + , mReaderCallback(nullptr) + , mLastDecodedTime(0) , mColorConverterBufferSize(0) , mNativeWindow(nullptr) , mPendingReleaseItemsLock("GonkVideoDecoderManager::mPendingReleaseItemsLock") + , mMonitor("GonkVideoDecoderManager") { MOZ_COUNT_CTOR(GonkVideoDecoderManager); mMimeType = aConfig.mMimeType; @@ -58,6 +64,7 @@ GonkVideoDecoderManager::GonkVideoDecoderManager( nsIntSize frameSize(mVideoWidth, mVideoHeight); mPicture = pictureRect; mInitialFrame = frameSize; + mHandler = new MessageHandler(this); mVideoListener = new VideoResourceListener(this); } @@ -69,7 +76,7 @@ GonkVideoDecoderManager::~GonkVideoDecoderManager() } nsRefPtr -GonkVideoDecoderManager::Init() +GonkVideoDecoderManager::Init(MediaDataDecoderCallback* aCallback) { nsIntSize displaySize(mDisplayWidth, mDisplayHeight); nsIntRect pictureRect(0, 0, mVideoWidth, mVideoHeight); @@ -94,19 +101,26 @@ GonkVideoDecoderManager::Init() return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__); } + mReaderCallback = aCallback; + mReaderTaskQueue = AbstractThread::GetCurrent()->AsTaskQueue(); MOZ_ASSERT(mReaderTaskQueue); - if (mDecodeLooper.get() != nullptr) { + if (mLooper.get() != nullptr) { return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__); } - - if (!InitLoopers(MediaData::VIDEO_DATA)) { + // Create ALooper + mLooper = new ALooper; + mManagerLooper = new ALooper; + mManagerLooper->setName("GonkVideoDecoderManager"); + // Register AMessage handler to ALooper. + mManagerLooper->registerHandler(mHandler); + // Start ALooper thread. + if (mLooper->start() != OK || mManagerLooper->start() != OK ) { return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__); } - nsRefPtr p = mInitPromise.Ensure(__func__); - mDecoder = MediaCodecProxy::CreateByType(mDecodeLooper, mMimeType.get(), false, mVideoListener); + mDecoder = MediaCodecProxy::CreateByType(mLooper, mMimeType.get(), false, mVideoListener); mDecoder->AsyncAskMediaCodec(); uint32_t capability = MediaCodecProxy::kEmptyCapability; @@ -118,6 +132,52 @@ GonkVideoDecoderManager::Init() return p; } +nsresult +GonkVideoDecoderManager::Input(MediaRawData* aSample) +{ + MonitorAutoLock mon(mMonitor); + nsRefPtr sample; + + if (!aSample) { + // It means EOS with empty sample. + sample = new MediaRawData(); + } else { + sample = aSample; + } + + mQueueSample.AppendElement(sample); + + status_t rv; + while (mQueueSample.Length()) { + nsRefPtr data = mQueueSample.ElementAt(0); + { + MonitorAutoUnlock mon_unlock(mMonitor); + rv = mDecoder->Input(reinterpret_cast(data->Data()), + data->Size(), + data->mTime, + 0); + } + if (rv == OK) { + mQueueSample.RemoveElementAt(0); + } else if (rv == -EAGAIN || rv == -ETIMEDOUT) { + // In most cases, EAGAIN or ETIMEOUT are safe because OMX can't fill + // buffer on time. + return NS_OK; + } else { + return NS_ERROR_UNEXPECTED; + } + } + + return NS_OK; +} + +bool +GonkVideoDecoderManager::HasQueuedSample() +{ + MonitorAutoLock mon(mMonitor); + return mQueueSample.Length(); +} + nsresult GonkVideoDecoderManager::CreateVideoData(int64_t aStreamOffset, VideoData **v) { @@ -137,12 +197,12 @@ GonkVideoDecoderManager::CreateVideoData(int64_t aStreamOffset, VideoData **v) return NS_ERROR_UNEXPECTED; } - if (mLastTime > timeUs) { + if (mLastDecodedTime > timeUs) { ReleaseVideoBuffer(); GVDM_LOG("Output decoded sample time is revert. time=%lld", timeUs); return NS_ERROR_NOT_AVAILABLE; } - mLastTime = timeUs; + mLastDecodedTime = timeUs; if (mVideoBuffer->range_length() == 0) { // Some decoders may return spurious empty buffers that we just want to ignore @@ -307,6 +367,27 @@ GonkVideoDecoderManager::SetVideoFormat() return false; } +nsresult +GonkVideoDecoderManager::Flush() +{ + if (mDecoder == nullptr) { + GVDM_LOG("Decoder is not inited"); + return NS_ERROR_UNEXPECTED; + } + { + MonitorAutoLock mon(mMonitor); + mQueueSample.Clear(); + } + + mLastDecodedTime = 0; + + if (mDecoder->flush() != OK) { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + // Blocks until decoded sample is produced by the deoder. nsresult GonkVideoDecoderManager::Output(int64_t aStreamOffset, @@ -435,7 +516,7 @@ GonkVideoDecoderManager::codecCanceled() mInitPromise.RejectIfExists(DecoderFailureReason::CANCELED, __func__); } -// Called on GonkDecoderManager::mTaskLooper thread. +// Called on GonkVideoDecoderManager::mManagerLooper thread. void GonkVideoDecoderManager::onMessageReceived(const sp &aMessage) { @@ -447,10 +528,26 @@ GonkVideoDecoderManager::onMessageReceived(const sp &aMessage) } default: - { - GonkDecoderManager::onMessageReceived(aMessage); + TRESPASS(); break; - } + } +} + +GonkVideoDecoderManager::MessageHandler::MessageHandler(GonkVideoDecoderManager *aManager) + : mManager(aManager) +{ +} + +GonkVideoDecoderManager::MessageHandler::~MessageHandler() +{ + mManager = nullptr; +} + +void +GonkVideoDecoderManager::MessageHandler::onMessageReceived(const android::sp &aMessage) +{ + if (mManager != nullptr) { + mManager->onMessageReceived(aMessage); } } @@ -555,7 +652,7 @@ void GonkVideoDecoderManager::PostReleaseVideoBuffer( } } sp notify = - new AMessage(kNotifyPostReleaseBuffer, id()); + new AMessage(kNotifyPostReleaseBuffer, mHandler->id()); notify->post(); } diff --git a/dom/media/platforms/gonk/GonkVideoDecoderManager.h b/dom/media/platforms/gonk/GonkVideoDecoderManager.h index 9a5a764dcd28..925cb1846915 100644 --- a/dom/media/platforms/gonk/GonkVideoDecoderManager.h +++ b/dom/media/platforms/gonk/GonkVideoDecoderManager.h @@ -7,11 +7,13 @@ #if !defined(GonkVideoDecoderManager_h_) #define GonkVideoDecoderManager_h_ +#include #include "nsRect.h" #include "GonkMediaDataDecoder.h" #include "mozilla/RefPtr.h" #include "I420ColorConverterHelper.h" #include "MediaCodecProxy.h" +#include #include "GonkNativeWindow.h" #include "GonkNativeWindowClient.h" #include "mozilla/layers/FenceUtils.h" @@ -20,6 +22,7 @@ using namespace android; namespace android { +struct ALooper; class MediaBuffer; struct MOZ_EXPORT AString; class GonkNativeWindow; @@ -39,13 +42,19 @@ public: GonkVideoDecoderManager(mozilla::layers::ImageContainer* aImageContainer, const VideoInfo& aConfig); - virtual ~GonkVideoDecoderManager(); + virtual ~GonkVideoDecoderManager() override; - nsRefPtr Init() override; + nsRefPtr Init(MediaDataDecoderCallback* aCallback) override; + + nsresult Input(MediaRawData* aSample) override; nsresult Output(int64_t aStreamOffset, nsRefPtr& aOutput) override; + nsresult Flush() override; + + bool HasQueuedSample() override; + static void RecycleCallback(TextureClient* aClient, void* aClosure); private: @@ -61,8 +70,23 @@ private: int32_t mCropRight = 0; int32_t mCropBottom = 0; }; + class MessageHandler : public android::AHandler + { + public: + MessageHandler(GonkVideoDecoderManager *aManager); + ~MessageHandler(); - void onMessageReceived(const android::sp &aMessage) override; + void onMessageReceived(const android::sp &aMessage) override; + + private: + // Forbidden + MessageHandler() = delete; + MessageHandler(const MessageHandler &rhs) = delete; + const MessageHandler &operator=(const MessageHandler &rhs) = delete; + + GonkVideoDecoderManager *mManager; + }; + friend class MessageHandler; class VideoResourceListener : public android::MediaCodecProxy::CodecResourceListener { @@ -95,6 +119,7 @@ private: // For codec resource management void codecReserved(); void codecCanceled(); + void onMessageReceived(const sp &aMessage); void ReleaseAllPendingVideoBuffers(); void PostReleaseVideoBuffer(android::MediaBuffer *aBuffer, @@ -111,10 +136,16 @@ private: android::MediaBuffer* mVideoBuffer; + MediaDataDecoderCallback* mReaderCallback; MediaInfo mInfo; android::sp mVideoListener; + android::sp mHandler; + android::sp mLooper; + android::sp mManagerLooper; FrameInfo mFrameInfo; + int64_t mLastDecodedTime; // The last decoded frame presentation time. + // color converter android::I420ColorConverterHelper mColorConverter; nsAutoArrayPtr mColorConverterBuffer; @@ -137,9 +168,17 @@ private: // The lock protects mPendingReleaseItems. Mutex mPendingReleaseItemsLock; - // This TaskQueue should be the same one in mDecodeCallback->OnReaderTaskQueue(). + // This monitor protects mQueueSample. + Monitor mMonitor; + + // This TaskQueue should be the same one in mReaderCallback->OnReaderTaskQueue(). // It is for codec resource mangement, decoding task should not dispatch to it. nsRefPtr mReaderTaskQueue; + + // An queue with the MP4 samples which are waiting to be sent into OMX. + // If an element is an empty MP4Sample, that menas EOS. There should not + // any sample be queued after EOS. + nsTArray> mQueueSample; }; } // namespace mozilla From 903a88eacce2b1f48e54934036fdcd3ff92983ac Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Wed, 7 Oct 2015 09:24:27 +0200 Subject: [PATCH 166/228] Backed out 1 changesets (bug 1101020) for landing with wrong bugnumber on a CLOSED TREE Backed out changeset 18d4a0ca8cc1 (bug 1101020) --- gfx/2d/PathHelpers.h | 26 +++--------- layout/base/nsLayoutUtils.cpp | 14 ------- layout/base/nsLayoutUtils.h | 11 ------ layout/mathml/nsMathMLFrame.cpp | 7 ++-- layout/reftests/mathml/radicalbar-1.html | 48 ----------------------- layout/reftests/mathml/radicalbar-1a.html | 48 ----------------------- layout/reftests/mathml/radicalbar-1b.html | 48 ----------------------- layout/reftests/mathml/radicalbar-1c.html | 48 ----------------------- layout/reftests/mathml/radicalbar-1d.html | 48 ----------------------- layout/reftests/mathml/radicalbar-1e.html | 48 ----------------------- layout/reftests/mathml/radicalbar-2.html | 47 ---------------------- layout/reftests/mathml/radicalbar-2a.html | 47 ---------------------- layout/reftests/mathml/radicalbar-2b.html | 47 ---------------------- layout/reftests/mathml/radicalbar-2c.html | 47 ---------------------- layout/reftests/mathml/radicalbar-2d.html | 47 ---------------------- layout/reftests/mathml/radicalbar-2e.html | 47 ---------------------- layout/reftests/mathml/radicalbar-3.html | 47 ---------------------- layout/reftests/mathml/radicalbar-3a.html | 47 ---------------------- layout/reftests/mathml/radicalbar-3b.html | 47 ---------------------- layout/reftests/mathml/radicalbar-3c.html | 47 ---------------------- layout/reftests/mathml/radicalbar-3d.html | 47 ---------------------- layout/reftests/mathml/radicalbar-3e.html | 47 ---------------------- layout/reftests/mathml/reftest.list | 18 --------- 23 files changed, 8 insertions(+), 920 deletions(-) delete mode 100644 layout/reftests/mathml/radicalbar-1.html delete mode 100644 layout/reftests/mathml/radicalbar-1a.html delete mode 100644 layout/reftests/mathml/radicalbar-1b.html delete mode 100644 layout/reftests/mathml/radicalbar-1c.html delete mode 100644 layout/reftests/mathml/radicalbar-1d.html delete mode 100644 layout/reftests/mathml/radicalbar-1e.html delete mode 100644 layout/reftests/mathml/radicalbar-2.html delete mode 100644 layout/reftests/mathml/radicalbar-2a.html delete mode 100644 layout/reftests/mathml/radicalbar-2b.html delete mode 100644 layout/reftests/mathml/radicalbar-2c.html delete mode 100644 layout/reftests/mathml/radicalbar-2d.html delete mode 100644 layout/reftests/mathml/radicalbar-2e.html delete mode 100644 layout/reftests/mathml/radicalbar-3.html delete mode 100644 layout/reftests/mathml/radicalbar-3a.html delete mode 100644 layout/reftests/mathml/radicalbar-3b.html delete mode 100644 layout/reftests/mathml/radicalbar-3c.html delete mode 100644 layout/reftests/mathml/radicalbar-3d.html delete mode 100644 layout/reftests/mathml/radicalbar-3e.html diff --git a/gfx/2d/PathHelpers.h b/gfx/2d/PathHelpers.h index 7a4fac98975d..4dbc0aac8fbe 100644 --- a/gfx/2d/PathHelpers.h +++ b/gfx/2d/PathHelpers.h @@ -352,14 +352,9 @@ extern UserDataKey sDisablePixelSnapping; * boundaries.) If on the other hand you stroking the rect with an odd valued * stroke width then the edges of the stroke will be antialiased (assuming an * AntialiasMode that does antialiasing). - * - * Empty snaps are those which result in a rectangle of 0 area. If they are - * disallowed, an axis is left unsnapped if the rounding process results in a - * length of 0. */ inline bool UserToDevicePixelSnapped(Rect& aRect, const DrawTarget& aDrawTarget, - bool aAllowScaleOr90DegreeRotate = false, - bool aAllowEmptySnaps = true) + bool aAllowScaleOr90DegreeRotate = false) { if (aDrawTarget.GetUserData(&sDisablePixelSnapping)) { return false; @@ -388,18 +383,8 @@ inline bool UserToDevicePixelSnapped(Rect& aRect, const DrawTarget& aDrawTarget, // We actually only need to check one of p2 and p4, since an affine // transform maps parallelograms to parallelograms. if (p2 == Point(p1.x, p3.y) || p2 == Point(p3.x, p1.y)) { - Point p1r = p1; - Point p3r = p3; - p1r.Round(); - p3r.Round(); - if (aAllowEmptySnaps || p1r.x != p3r.x) { - p1.x = p1r.x; - p3.x = p3r.x; - } - if (aAllowEmptySnaps || p1r.y != p3r.y) { - p1.y = p1r.y; - p3.y = p3r.y; - } + p1.Round(); + p3.Round(); aRect.MoveTo(Point(std::min(p1.x, p3.x), std::min(p1.y, p3.y))); aRect.SizeTo(Size(std::max(p1.x, p3.x) - aRect.X(), @@ -415,11 +400,10 @@ inline bool UserToDevicePixelSnapped(Rect& aRect, const DrawTarget& aDrawTarget, * aRect is not transformed to device space. */ inline bool MaybeSnapToDevicePixels(Rect& aRect, const DrawTarget& aDrawTarget, - bool aAllowScaleOr90DegreeRotate = false, - bool aAllowEmptySnaps = true) + bool aAllowScaleOr90DegreeRotate = false) { if (UserToDevicePixelSnapped(aRect, aDrawTarget, - aAllowScaleOr90DegreeRotate, aAllowEmptySnaps)) { + aAllowScaleOr90DegreeRotate)) { // Since UserToDevicePixelSnapped returned true we know there is no // rotation/skew in 'mat', so we can just use TransformBounds() here. Matrix mat = aDrawTarget.GetTransform(); diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 8e33bd82ebae..0d6ccd8a8f48 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -8101,20 +8101,6 @@ Rect NSRectToSnappedRect(const nsRect& aRect, double aAppUnitsPerPixel, MaybeSnapToDevicePixels(rect, aSnapDT, true); return rect; } -// Similar to a snapped rect, except an axis is left unsnapped if the snapping -// process results in a length of 0. -Rect NSRectToNonEmptySnappedRect(const nsRect& aRect, double aAppUnitsPerPixel, - const gfx::DrawTarget& aSnapDT) -{ - // Note that by making aAppUnitsPerPixel a double we're doing floating-point - // division using a larger type and avoiding rounding error. - Rect rect(Float(aRect.x / aAppUnitsPerPixel), - Float(aRect.y / aAppUnitsPerPixel), - Float(aRect.width / aAppUnitsPerPixel), - Float(aRect.height / aAppUnitsPerPixel)); - MaybeSnapToDevicePixels(rect, aSnapDT, true, false); - return rect; -} void StrokeLineWithSnapping(const nsPoint& aP1, const nsPoint& aP2, int32_t aAppUnitsPerDevPixel, diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index f8c68f832e7f..d74022b5005b 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -2860,17 +2860,6 @@ gfx::Rect NSRectToRect(const nsRect& aRect, double aAppUnitsPerPixel); gfx::Rect NSRectToSnappedRect(const nsRect& aRect, double aAppUnitsPerPixel, const gfx::DrawTarget& aSnapDT); -/** -* Converts, where possible, an nsRect in app units to a Moz2D Rect in pixels -* (whether those are device pixels or CSS px depends on what the caller -* chooses to pass as aAppUnitsPerPixel). -* -* If snapping results in a rectangle with zero width or height, the affected -* coordinates are left unsnapped -*/ -gfx::Rect NSRectToNonEmptySnappedRect(const nsRect& aRect, double aAppUnitsPerPixel, - const gfx::DrawTarget& aSnapDT); - void StrokeLineWithSnapping(const nsPoint& aP1, const nsPoint& aP2, int32_t aAppUnitsPerDevPixel, gfx::DrawTarget& aDrawTarget, diff --git a/layout/mathml/nsMathMLFrame.cpp b/layout/mathml/nsMathMLFrame.cpp index 66ad07d347ec..db541ada40c4 100644 --- a/layout/mathml/nsMathMLFrame.cpp +++ b/layout/mathml/nsMathMLFrame.cpp @@ -363,10 +363,9 @@ void nsDisplayMathMLBar::Paint(nsDisplayListBuilder* aBuilder, { // paint the bar with the current text color DrawTarget* drawTarget = aCtx->GetDrawTarget(); - Rect rect = - NSRectToNonEmptySnappedRect(mRect + ToReferenceFrame(), - mFrame->PresContext()->AppUnitsPerDevPixel(), - *drawTarget); + Rect rect = NSRectToSnappedRect(mRect + ToReferenceFrame(), + mFrame->PresContext()->AppUnitsPerDevPixel(), + *drawTarget); ColorPattern color(ToDeviceColor( mFrame->GetVisitedDependentColor(eCSSProperty_color))); drawTarget->FillRect(rect, color); diff --git a/layout/reftests/mathml/radicalbar-1.html b/layout/reftests/mathml/radicalbar-1.html deleted file mode 100644 index 7ee38149dd20..000000000000 --- a/layout/reftests/mathml/radicalbar-1.html +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - -
- - - diff --git a/layout/reftests/mathml/radicalbar-1a.html b/layout/reftests/mathml/radicalbar-1a.html deleted file mode 100644 index 3b43eb90922d..000000000000 --- a/layout/reftests/mathml/radicalbar-1a.html +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - -
- - - diff --git a/layout/reftests/mathml/radicalbar-1b.html b/layout/reftests/mathml/radicalbar-1b.html deleted file mode 100644 index 3d49caa38dde..000000000000 --- a/layout/reftests/mathml/radicalbar-1b.html +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - -
- - - diff --git a/layout/reftests/mathml/radicalbar-1c.html b/layout/reftests/mathml/radicalbar-1c.html deleted file mode 100644 index 3ebff2420370..000000000000 --- a/layout/reftests/mathml/radicalbar-1c.html +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - -
- - - diff --git a/layout/reftests/mathml/radicalbar-1d.html b/layout/reftests/mathml/radicalbar-1d.html deleted file mode 100644 index 70c8ed936092..000000000000 --- a/layout/reftests/mathml/radicalbar-1d.html +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - -
- - - diff --git a/layout/reftests/mathml/radicalbar-1e.html b/layout/reftests/mathml/radicalbar-1e.html deleted file mode 100644 index 560c8175cc0b..000000000000 --- a/layout/reftests/mathml/radicalbar-1e.html +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - -
- - - diff --git a/layout/reftests/mathml/radicalbar-2.html b/layout/reftests/mathml/radicalbar-2.html deleted file mode 100644 index 140d0e037ba2..000000000000 --- a/layout/reftests/mathml/radicalbar-2.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - -
- - diff --git a/layout/reftests/mathml/radicalbar-2a.html b/layout/reftests/mathml/radicalbar-2a.html deleted file mode 100644 index ff31625f0678..000000000000 --- a/layout/reftests/mathml/radicalbar-2a.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - -
- - diff --git a/layout/reftests/mathml/radicalbar-2b.html b/layout/reftests/mathml/radicalbar-2b.html deleted file mode 100644 index 8d2736fc60b4..000000000000 --- a/layout/reftests/mathml/radicalbar-2b.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - -
- - diff --git a/layout/reftests/mathml/radicalbar-2c.html b/layout/reftests/mathml/radicalbar-2c.html deleted file mode 100644 index 1e9f01777490..000000000000 --- a/layout/reftests/mathml/radicalbar-2c.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - -
- - diff --git a/layout/reftests/mathml/radicalbar-2d.html b/layout/reftests/mathml/radicalbar-2d.html deleted file mode 100644 index b92ed920f067..000000000000 --- a/layout/reftests/mathml/radicalbar-2d.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - -
- - diff --git a/layout/reftests/mathml/radicalbar-2e.html b/layout/reftests/mathml/radicalbar-2e.html deleted file mode 100644 index 4685d0318fe6..000000000000 --- a/layout/reftests/mathml/radicalbar-2e.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - -
- - diff --git a/layout/reftests/mathml/radicalbar-3.html b/layout/reftests/mathml/radicalbar-3.html deleted file mode 100644 index 929ff534da64..000000000000 --- a/layout/reftests/mathml/radicalbar-3.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - -
- - diff --git a/layout/reftests/mathml/radicalbar-3a.html b/layout/reftests/mathml/radicalbar-3a.html deleted file mode 100644 index 5708e38a79a7..000000000000 --- a/layout/reftests/mathml/radicalbar-3a.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - -
- - diff --git a/layout/reftests/mathml/radicalbar-3b.html b/layout/reftests/mathml/radicalbar-3b.html deleted file mode 100644 index 8343654acb35..000000000000 --- a/layout/reftests/mathml/radicalbar-3b.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - -
- - diff --git a/layout/reftests/mathml/radicalbar-3c.html b/layout/reftests/mathml/radicalbar-3c.html deleted file mode 100644 index c5f5e5a65eb5..000000000000 --- a/layout/reftests/mathml/radicalbar-3c.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - -
- - diff --git a/layout/reftests/mathml/radicalbar-3d.html b/layout/reftests/mathml/radicalbar-3d.html deleted file mode 100644 index 99e7790fb04e..000000000000 --- a/layout/reftests/mathml/radicalbar-3d.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - -
- - diff --git a/layout/reftests/mathml/radicalbar-3e.html b/layout/reftests/mathml/radicalbar-3e.html deleted file mode 100644 index bd361157f664..000000000000 --- a/layout/reftests/mathml/radicalbar-3e.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - -
- - diff --git a/layout/reftests/mathml/reftest.list b/layout/reftests/mathml/reftest.list index 910e53ddb5df..de7b5fb220e4 100644 --- a/layout/reftests/mathml/reftest.list +++ b/layout/reftests/mathml/reftest.list @@ -366,21 +366,3 @@ fails-if(winWidget) == mfrac-D-2.html mfrac-D-2-ref.html test-pref(dom.webcomponents.enabled,true) == shadow-dom-1.html shadow-dom-1-ref.html pref(font.size.inflation.emPerLine,25) == font-inflation-1.html font-inflation-1-ref.html test-pref(font.minimum-size.x-math,40) == default-font.html default-font-ref.html -!= radicalbar-1.html about:blank -!= radicalbar-1a.html about:blank -!= radicalbar-1b.html about:blank -!= radicalbar-1c.html about:blank -!= radicalbar-1d.html about:blank -!= radicalbar-1e.html about:blank -!= radicalbar-2.html about:blank -!= radicalbar-2a.html about:blank -!= radicalbar-2b.html about:blank -!= radicalbar-2c.html about:blank -!= radicalbar-2d.html about:blank -!= radicalbar-2e.html about:blank -!= radicalbar-3.html about:blank -!= radicalbar-3a.html about:blank -!= radicalbar-3b.html about:blank -!= radicalbar-3c.html about:blank -!= radicalbar-3d.html about:blank -!= radicalbar-3e.html about:blank From 590b916a4a080e48fe716558ec203edc282dac56 Mon Sep 17 00:00:00 2001 From: James Kitchener Date: Mon, 5 Oct 2015 05:00:00 +0200 Subject: [PATCH 167/228] Bug 1011020 - Add the ability to fall back to not snapping, if snapping results in a zero area rect r=roc - relanding with correct bug number on a CLOSED TREE --- gfx/2d/PathHelpers.h | 26 +++++++++--- layout/base/nsLayoutUtils.cpp | 14 +++++++ layout/base/nsLayoutUtils.h | 11 ++++++ layout/mathml/nsMathMLFrame.cpp | 7 ++-- layout/reftests/mathml/radicalbar-1.html | 48 +++++++++++++++++++++++ layout/reftests/mathml/radicalbar-1a.html | 48 +++++++++++++++++++++++ layout/reftests/mathml/radicalbar-1b.html | 48 +++++++++++++++++++++++ layout/reftests/mathml/radicalbar-1c.html | 48 +++++++++++++++++++++++ layout/reftests/mathml/radicalbar-1d.html | 48 +++++++++++++++++++++++ layout/reftests/mathml/radicalbar-1e.html | 48 +++++++++++++++++++++++ layout/reftests/mathml/radicalbar-2.html | 47 ++++++++++++++++++++++ layout/reftests/mathml/radicalbar-2a.html | 47 ++++++++++++++++++++++ layout/reftests/mathml/radicalbar-2b.html | 47 ++++++++++++++++++++++ layout/reftests/mathml/radicalbar-2c.html | 47 ++++++++++++++++++++++ layout/reftests/mathml/radicalbar-2d.html | 47 ++++++++++++++++++++++ layout/reftests/mathml/radicalbar-2e.html | 47 ++++++++++++++++++++++ layout/reftests/mathml/radicalbar-3.html | 47 ++++++++++++++++++++++ layout/reftests/mathml/radicalbar-3a.html | 47 ++++++++++++++++++++++ layout/reftests/mathml/radicalbar-3b.html | 47 ++++++++++++++++++++++ layout/reftests/mathml/radicalbar-3c.html | 47 ++++++++++++++++++++++ layout/reftests/mathml/radicalbar-3d.html | 47 ++++++++++++++++++++++ layout/reftests/mathml/radicalbar-3e.html | 47 ++++++++++++++++++++++ layout/reftests/mathml/reftest.list | 18 +++++++++ 23 files changed, 920 insertions(+), 8 deletions(-) create mode 100644 layout/reftests/mathml/radicalbar-1.html create mode 100644 layout/reftests/mathml/radicalbar-1a.html create mode 100644 layout/reftests/mathml/radicalbar-1b.html create mode 100644 layout/reftests/mathml/radicalbar-1c.html create mode 100644 layout/reftests/mathml/radicalbar-1d.html create mode 100644 layout/reftests/mathml/radicalbar-1e.html create mode 100644 layout/reftests/mathml/radicalbar-2.html create mode 100644 layout/reftests/mathml/radicalbar-2a.html create mode 100644 layout/reftests/mathml/radicalbar-2b.html create mode 100644 layout/reftests/mathml/radicalbar-2c.html create mode 100644 layout/reftests/mathml/radicalbar-2d.html create mode 100644 layout/reftests/mathml/radicalbar-2e.html create mode 100644 layout/reftests/mathml/radicalbar-3.html create mode 100644 layout/reftests/mathml/radicalbar-3a.html create mode 100644 layout/reftests/mathml/radicalbar-3b.html create mode 100644 layout/reftests/mathml/radicalbar-3c.html create mode 100644 layout/reftests/mathml/radicalbar-3d.html create mode 100644 layout/reftests/mathml/radicalbar-3e.html diff --git a/gfx/2d/PathHelpers.h b/gfx/2d/PathHelpers.h index 4dbc0aac8fbe..7a4fac98975d 100644 --- a/gfx/2d/PathHelpers.h +++ b/gfx/2d/PathHelpers.h @@ -352,9 +352,14 @@ extern UserDataKey sDisablePixelSnapping; * boundaries.) If on the other hand you stroking the rect with an odd valued * stroke width then the edges of the stroke will be antialiased (assuming an * AntialiasMode that does antialiasing). + * + * Empty snaps are those which result in a rectangle of 0 area. If they are + * disallowed, an axis is left unsnapped if the rounding process results in a + * length of 0. */ inline bool UserToDevicePixelSnapped(Rect& aRect, const DrawTarget& aDrawTarget, - bool aAllowScaleOr90DegreeRotate = false) + bool aAllowScaleOr90DegreeRotate = false, + bool aAllowEmptySnaps = true) { if (aDrawTarget.GetUserData(&sDisablePixelSnapping)) { return false; @@ -383,8 +388,18 @@ inline bool UserToDevicePixelSnapped(Rect& aRect, const DrawTarget& aDrawTarget, // We actually only need to check one of p2 and p4, since an affine // transform maps parallelograms to parallelograms. if (p2 == Point(p1.x, p3.y) || p2 == Point(p3.x, p1.y)) { - p1.Round(); - p3.Round(); + Point p1r = p1; + Point p3r = p3; + p1r.Round(); + p3r.Round(); + if (aAllowEmptySnaps || p1r.x != p3r.x) { + p1.x = p1r.x; + p3.x = p3r.x; + } + if (aAllowEmptySnaps || p1r.y != p3r.y) { + p1.y = p1r.y; + p3.y = p3r.y; + } aRect.MoveTo(Point(std::min(p1.x, p3.x), std::min(p1.y, p3.y))); aRect.SizeTo(Size(std::max(p1.x, p3.x) - aRect.X(), @@ -400,10 +415,11 @@ inline bool UserToDevicePixelSnapped(Rect& aRect, const DrawTarget& aDrawTarget, * aRect is not transformed to device space. */ inline bool MaybeSnapToDevicePixels(Rect& aRect, const DrawTarget& aDrawTarget, - bool aAllowScaleOr90DegreeRotate = false) + bool aAllowScaleOr90DegreeRotate = false, + bool aAllowEmptySnaps = true) { if (UserToDevicePixelSnapped(aRect, aDrawTarget, - aAllowScaleOr90DegreeRotate)) { + aAllowScaleOr90DegreeRotate, aAllowEmptySnaps)) { // Since UserToDevicePixelSnapped returned true we know there is no // rotation/skew in 'mat', so we can just use TransformBounds() here. Matrix mat = aDrawTarget.GetTransform(); diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 0d6ccd8a8f48..8e33bd82ebae 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -8101,6 +8101,20 @@ Rect NSRectToSnappedRect(const nsRect& aRect, double aAppUnitsPerPixel, MaybeSnapToDevicePixels(rect, aSnapDT, true); return rect; } +// Similar to a snapped rect, except an axis is left unsnapped if the snapping +// process results in a length of 0. +Rect NSRectToNonEmptySnappedRect(const nsRect& aRect, double aAppUnitsPerPixel, + const gfx::DrawTarget& aSnapDT) +{ + // Note that by making aAppUnitsPerPixel a double we're doing floating-point + // division using a larger type and avoiding rounding error. + Rect rect(Float(aRect.x / aAppUnitsPerPixel), + Float(aRect.y / aAppUnitsPerPixel), + Float(aRect.width / aAppUnitsPerPixel), + Float(aRect.height / aAppUnitsPerPixel)); + MaybeSnapToDevicePixels(rect, aSnapDT, true, false); + return rect; +} void StrokeLineWithSnapping(const nsPoint& aP1, const nsPoint& aP2, int32_t aAppUnitsPerDevPixel, diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index d74022b5005b..f8c68f832e7f 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -2860,6 +2860,17 @@ gfx::Rect NSRectToRect(const nsRect& aRect, double aAppUnitsPerPixel); gfx::Rect NSRectToSnappedRect(const nsRect& aRect, double aAppUnitsPerPixel, const gfx::DrawTarget& aSnapDT); +/** +* Converts, where possible, an nsRect in app units to a Moz2D Rect in pixels +* (whether those are device pixels or CSS px depends on what the caller +* chooses to pass as aAppUnitsPerPixel). +* +* If snapping results in a rectangle with zero width or height, the affected +* coordinates are left unsnapped +*/ +gfx::Rect NSRectToNonEmptySnappedRect(const nsRect& aRect, double aAppUnitsPerPixel, + const gfx::DrawTarget& aSnapDT); + void StrokeLineWithSnapping(const nsPoint& aP1, const nsPoint& aP2, int32_t aAppUnitsPerDevPixel, gfx::DrawTarget& aDrawTarget, diff --git a/layout/mathml/nsMathMLFrame.cpp b/layout/mathml/nsMathMLFrame.cpp index db541ada40c4..66ad07d347ec 100644 --- a/layout/mathml/nsMathMLFrame.cpp +++ b/layout/mathml/nsMathMLFrame.cpp @@ -363,9 +363,10 @@ void nsDisplayMathMLBar::Paint(nsDisplayListBuilder* aBuilder, { // paint the bar with the current text color DrawTarget* drawTarget = aCtx->GetDrawTarget(); - Rect rect = NSRectToSnappedRect(mRect + ToReferenceFrame(), - mFrame->PresContext()->AppUnitsPerDevPixel(), - *drawTarget); + Rect rect = + NSRectToNonEmptySnappedRect(mRect + ToReferenceFrame(), + mFrame->PresContext()->AppUnitsPerDevPixel(), + *drawTarget); ColorPattern color(ToDeviceColor( mFrame->GetVisitedDependentColor(eCSSProperty_color))); drawTarget->FillRect(rect, color); diff --git a/layout/reftests/mathml/radicalbar-1.html b/layout/reftests/mathml/radicalbar-1.html new file mode 100644 index 000000000000..7ee38149dd20 --- /dev/null +++ b/layout/reftests/mathml/radicalbar-1.html @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + +
+ + + diff --git a/layout/reftests/mathml/radicalbar-1a.html b/layout/reftests/mathml/radicalbar-1a.html new file mode 100644 index 000000000000..3b43eb90922d --- /dev/null +++ b/layout/reftests/mathml/radicalbar-1a.html @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + +
+ + + diff --git a/layout/reftests/mathml/radicalbar-1b.html b/layout/reftests/mathml/radicalbar-1b.html new file mode 100644 index 000000000000..3d49caa38dde --- /dev/null +++ b/layout/reftests/mathml/radicalbar-1b.html @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + +
+ + + diff --git a/layout/reftests/mathml/radicalbar-1c.html b/layout/reftests/mathml/radicalbar-1c.html new file mode 100644 index 000000000000..3ebff2420370 --- /dev/null +++ b/layout/reftests/mathml/radicalbar-1c.html @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + +
+ + + diff --git a/layout/reftests/mathml/radicalbar-1d.html b/layout/reftests/mathml/radicalbar-1d.html new file mode 100644 index 000000000000..70c8ed936092 --- /dev/null +++ b/layout/reftests/mathml/radicalbar-1d.html @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + +
+ + + diff --git a/layout/reftests/mathml/radicalbar-1e.html b/layout/reftests/mathml/radicalbar-1e.html new file mode 100644 index 000000000000..560c8175cc0b --- /dev/null +++ b/layout/reftests/mathml/radicalbar-1e.html @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + +
+ + + diff --git a/layout/reftests/mathml/radicalbar-2.html b/layout/reftests/mathml/radicalbar-2.html new file mode 100644 index 000000000000..140d0e037ba2 --- /dev/null +++ b/layout/reftests/mathml/radicalbar-2.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + +
+ + diff --git a/layout/reftests/mathml/radicalbar-2a.html b/layout/reftests/mathml/radicalbar-2a.html new file mode 100644 index 000000000000..ff31625f0678 --- /dev/null +++ b/layout/reftests/mathml/radicalbar-2a.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + +
+ + diff --git a/layout/reftests/mathml/radicalbar-2b.html b/layout/reftests/mathml/radicalbar-2b.html new file mode 100644 index 000000000000..8d2736fc60b4 --- /dev/null +++ b/layout/reftests/mathml/radicalbar-2b.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + +
+ + diff --git a/layout/reftests/mathml/radicalbar-2c.html b/layout/reftests/mathml/radicalbar-2c.html new file mode 100644 index 000000000000..1e9f01777490 --- /dev/null +++ b/layout/reftests/mathml/radicalbar-2c.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + +
+ + diff --git a/layout/reftests/mathml/radicalbar-2d.html b/layout/reftests/mathml/radicalbar-2d.html new file mode 100644 index 000000000000..b92ed920f067 --- /dev/null +++ b/layout/reftests/mathml/radicalbar-2d.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + +
+ + diff --git a/layout/reftests/mathml/radicalbar-2e.html b/layout/reftests/mathml/radicalbar-2e.html new file mode 100644 index 000000000000..4685d0318fe6 --- /dev/null +++ b/layout/reftests/mathml/radicalbar-2e.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + +
+ + diff --git a/layout/reftests/mathml/radicalbar-3.html b/layout/reftests/mathml/radicalbar-3.html new file mode 100644 index 000000000000..929ff534da64 --- /dev/null +++ b/layout/reftests/mathml/radicalbar-3.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + +
+ + diff --git a/layout/reftests/mathml/radicalbar-3a.html b/layout/reftests/mathml/radicalbar-3a.html new file mode 100644 index 000000000000..5708e38a79a7 --- /dev/null +++ b/layout/reftests/mathml/radicalbar-3a.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + +
+ + diff --git a/layout/reftests/mathml/radicalbar-3b.html b/layout/reftests/mathml/radicalbar-3b.html new file mode 100644 index 000000000000..8343654acb35 --- /dev/null +++ b/layout/reftests/mathml/radicalbar-3b.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + +
+ + diff --git a/layout/reftests/mathml/radicalbar-3c.html b/layout/reftests/mathml/radicalbar-3c.html new file mode 100644 index 000000000000..c5f5e5a65eb5 --- /dev/null +++ b/layout/reftests/mathml/radicalbar-3c.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + +
+ + diff --git a/layout/reftests/mathml/radicalbar-3d.html b/layout/reftests/mathml/radicalbar-3d.html new file mode 100644 index 000000000000..99e7790fb04e --- /dev/null +++ b/layout/reftests/mathml/radicalbar-3d.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + +
+ + diff --git a/layout/reftests/mathml/radicalbar-3e.html b/layout/reftests/mathml/radicalbar-3e.html new file mode 100644 index 000000000000..bd361157f664 --- /dev/null +++ b/layout/reftests/mathml/radicalbar-3e.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + +
+ + diff --git a/layout/reftests/mathml/reftest.list b/layout/reftests/mathml/reftest.list index de7b5fb220e4..910e53ddb5df 100644 --- a/layout/reftests/mathml/reftest.list +++ b/layout/reftests/mathml/reftest.list @@ -366,3 +366,21 @@ fails-if(winWidget) == mfrac-D-2.html mfrac-D-2-ref.html test-pref(dom.webcomponents.enabled,true) == shadow-dom-1.html shadow-dom-1-ref.html pref(font.size.inflation.emPerLine,25) == font-inflation-1.html font-inflation-1-ref.html test-pref(font.minimum-size.x-math,40) == default-font.html default-font-ref.html +!= radicalbar-1.html about:blank +!= radicalbar-1a.html about:blank +!= radicalbar-1b.html about:blank +!= radicalbar-1c.html about:blank +!= radicalbar-1d.html about:blank +!= radicalbar-1e.html about:blank +!= radicalbar-2.html about:blank +!= radicalbar-2a.html about:blank +!= radicalbar-2b.html about:blank +!= radicalbar-2c.html about:blank +!= radicalbar-2d.html about:blank +!= radicalbar-2e.html about:blank +!= radicalbar-3.html about:blank +!= radicalbar-3a.html about:blank +!= radicalbar-3b.html about:blank +!= radicalbar-3c.html about:blank +!= radicalbar-3d.html about:blank +!= radicalbar-3e.html about:blank From 41bc4391c942925ecbdb7610ea97d486568c818a Mon Sep 17 00:00:00 2001 From: Nigel Babu Date: Wed, 7 Oct 2015 13:43:10 +0530 Subject: [PATCH 168/228] Backed out changeset 67b7e1825a7f (bug 1212164) for depending on bug 1206977 --- dom/media/MediaFormatReader.cpp | 8 ++------ dom/media/MediaFormatReader.h | 3 +-- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp index 6b0af2bcdf2b..c1f79a7c14bd 100644 --- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -63,10 +63,9 @@ MediaFormatReader::MediaFormatReader(AbstractMediaDecoder* aDecoder, MediaDataDemuxer* aDemuxer, TaskQueue* aBorrowedTaskQueue) : MediaDecoderReader(aDecoder, aBorrowedTaskQueue) + , mDemuxer(aDemuxer) , mAudio(this, MediaData::AUDIO_DATA, Preferences::GetUint("media.audio-decode-ahead", 2)) , mVideo(this, MediaData::VIDEO_DATA, Preferences::GetUint("media.video-decode-ahead", 2)) - , mDemuxer(aDemuxer) - , mDemuxerInitDone(false) , mLastReportedNumDecodedFrames(0) , mLayersBackendType(layers::LayersBackend::LAYERS_NONE) , mInitDone(false) @@ -273,8 +272,6 @@ MediaFormatReader::OnDemuxerInitDone(nsresult) MOZ_ASSERT(OnTaskQueue()); mDemuxerInitRequest.Complete(); - mDemuxerInitDone = true; - // To decode, we need valid video and a place to put it. bool videoActive = !!mDemuxer->GetNumberTracks(TrackInfo::kVideoTrack) && mDecoder->GetImageContainer(); @@ -1596,8 +1593,7 @@ MediaFormatReader::NotifyDemuxer(uint32_t aLength, int64_t aOffset) MOZ_ASSERT(OnTaskQueue()); LOGV("aLength=%u, aOffset=%lld", aLength, aOffset); - if (mShutdown || !mDemuxer || - (!mDemuxerInitDone && !mDemuxerInitRequest.Exists())) { + if (mShutdown || !mDemuxer) { return; } diff --git a/dom/media/MediaFormatReader.h b/dom/media/MediaFormatReader.h index 64f1d5c92112..85951ab12df6 100644 --- a/dom/media/MediaFormatReader.h +++ b/dom/media/MediaFormatReader.h @@ -152,6 +152,7 @@ private: size_t SizeOfQueue(TrackType aTrack); + nsRefPtr mDemuxer; nsRefPtr mPlatform; class DecoderCallback : public MediaDataDecoderCallback { @@ -354,8 +355,6 @@ private: void OnDecoderInitFailed(MediaDataDecoder::DecoderFailureReason aReason); // Demuxer objects. - nsRefPtr mDemuxer; - bool mDemuxerInitDone; void OnDemuxerInitDone(nsresult); void OnDemuxerInitFailed(DemuxerFailureReason aFailure); MozPromiseRequestHolder mDemuxerInitRequest; From 1a01355c4fe37698356863da3017e7f92325a210 Mon Sep 17 00:00:00 2001 From: Nigel Babu Date: Wed, 7 Oct 2015 13:43:39 +0530 Subject: [PATCH 169/228] Backed out 16 changesets (bug 1206977, bug 1211652, bug 1211335) for linux bc7 bustage ON A CLOSED TREE Backed out changeset 51b1b076a386 (bug 1206977) Backed out changeset dec7c35469d1 (bug 1206977) Backed out changeset bf9ddc78b394 (bug 1206977) Backed out changeset 08f5cff5aa12 (bug 1206977) Backed out changeset e4e91de99867 (bug 1206977) Backed out changeset 696ecf2e2947 (bug 1206977) Backed out changeset ab2d524a9b35 (bug 1206977) Backed out changeset d66be0e4547f (bug 1206977) Backed out changeset 64c58afbd6c1 (bug 1206977) Backed out changeset eb10d09015e1 (bug 1206977) Backed out changeset 042959216393 (bug 1206977) Backed out changeset 7e0de7f62202 (bug 1206977) Backed out changeset 3d095569f6ba (bug 1206977) Backed out changeset 041418a07ae5 (bug 1206977) Backed out changeset 654970da23e4 (bug 1211335) Backed out changeset 8ba8e24a84d3 (bug 1211652) --- dom/media/MP3Decoder.cpp | 48 +- dom/media/MediaFormatReader.cpp | 38 +- dom/media/MediaFormatReader.h | 6 +- dom/media/fmp4/MP4Decoder.cpp | 179 ++++++- dom/media/fmp4/MP4Decoder.h | 2 + dom/media/mediasource/test/mochitest.ini | 2 - .../mediasource/test/test_Sequence_mp4.html | 39 -- dom/media/platforms/PDMFactory.cpp | 275 ----------- dom/media/platforms/PDMFactory.h | 73 --- dom/media/platforms/PlatformDecoderModule.cpp | 280 +++++++++++ dom/media/platforms/PlatformDecoderModule.h | 92 +++- .../agnostic/AgnosticDecoderModule.cpp | 61 --- .../agnostic/AgnosticDecoderModule.h | 39 -- .../platforms/agnostic/BlankDecoderModule.cpp | 22 + .../agnostic/eme/EMEDecoderModule.cpp | 18 +- .../platforms/agnostic/eme/EMEDecoderModule.h | 16 +- .../platforms/agnostic/gmp/GMPDecoderModule.h | 8 - .../platforms/apple/AppleDecoderModule.cpp | 4 +- .../platforms/ffmpeg/FFmpegDataDecoder.cpp | 28 +- .../platforms/ffmpeg/FFmpegDataDecoder.h | 2 - .../platforms/ffmpeg/FFmpegDecoderModule.h | 12 +- .../platforms/ffmpeg/FFmpegRuntimeLinker.cpp | 6 - .../platforms/ffmpeg/FFmpegRuntimeLinker.h | 2 - dom/media/platforms/moz.build | 4 - dom/media/webm/AudioDecoder.cpp | 12 +- dom/media/webm/IntelWebMVideoDecoder.cpp | 443 ++++++++++++++++++ dom/media/webm/IntelWebMVideoDecoder.h | 97 ++++ dom/media/webm/SoftwareWebMVideoDecoder.cpp | 10 +- dom/media/webm/SoftwareWebMVideoDecoder.h | 4 +- dom/media/webm/WebMReader.cpp | 51 +- dom/media/webm/WebMReader.h | 13 +- dom/media/webm/moz.build | 5 + 32 files changed, 1279 insertions(+), 612 deletions(-) delete mode 100644 dom/media/mediasource/test/test_Sequence_mp4.html delete mode 100644 dom/media/platforms/PDMFactory.cpp delete mode 100644 dom/media/platforms/PDMFactory.h delete mode 100644 dom/media/platforms/agnostic/AgnosticDecoderModule.cpp delete mode 100644 dom/media/platforms/agnostic/AgnosticDecoderModule.h create mode 100644 dom/media/webm/IntelWebMVideoDecoder.cpp create mode 100644 dom/media/webm/IntelWebMVideoDecoder.h diff --git a/dom/media/MP3Decoder.cpp b/dom/media/MP3Decoder.cpp index c4bf6bab426e..c6415a26ce27 100644 --- a/dom/media/MP3Decoder.cpp +++ b/dom/media/MP3Decoder.cpp @@ -10,7 +10,7 @@ #include "MediaFormatReader.h" #include "MP3Demuxer.h" #include "mozilla/Preferences.h" -#include "PDMFactory.h" +#include "PlatformDecoderModule.h" namespace mozilla { @@ -29,12 +29,50 @@ MP3Decoder::CreateStateMachine() { return new MediaDecoderStateMachine(this, reader); } +static already_AddRefed +CreateTestMP3Decoder(AudioInfo& aConfig) +{ + PlatformDecoderModule::Init(); + + nsRefPtr platform = PlatformDecoderModule::Create(); + if (!platform || !platform->SupportsMimeType(aConfig.mMimeType)) { + return nullptr; + } + + nsRefPtr decoder( + platform->CreateDecoder(aConfig, nullptr, nullptr)); + if (!decoder) { + return nullptr; + } + + return decoder.forget(); +} + +static bool +CanCreateMP3Decoder() +{ + static bool haveCachedResult = false; + static bool result = false; + if (haveCachedResult) { + return result; + } + AudioInfo config; + config.mMimeType = "audio/mpeg"; + config.mRate = 48000; + config.mChannels = 2; + config.mBitDepth = 16; + nsRefPtr decoder(CreateTestMP3Decoder(config)); + if (decoder) { + result = true; + } + haveCachedResult = true; + return result; +} + /* static */ bool MP3Decoder::IsEnabled() { - PDMFactory::Init(); - nsRefPtr platform = new PDMFactory(); - return platform->SupportsMimeType(NS_LITERAL_CSTRING("audio/mpeg")); + return CanCreateMP3Decoder(); } /* static */ @@ -42,7 +80,7 @@ bool MP3Decoder::CanHandleMediaType(const nsACString& aType, const nsAString& aCodecs) { if (aType.EqualsASCII("audio/mp3") || aType.EqualsASCII("audio/mpeg")) { - return IsEnabled() && + return CanCreateMP3Decoder() && (aCodecs.IsEmpty() || aCodecs.EqualsASCII("mp3")); } return false; diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp index c1f79a7c14bd..be12573a1c8d 100644 --- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -169,7 +169,7 @@ nsresult MediaFormatReader::Init(MediaDecoderReader* aCloneDonor) { MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread."); - PDMFactory::Init(); + PlatformDecoderModule::Init(); InitLayersBackendType(); @@ -236,6 +236,20 @@ MediaFormatReader::IsWaitingOnCDMResource() { #endif } +bool +MediaFormatReader::IsSupportedAudioMimeType(const nsACString& aMimeType) +{ + return mPlatform && (mPlatform->SupportsMimeType(aMimeType) || + PlatformDecoderModule::AgnosticMimeType(aMimeType)); +} + +bool +MediaFormatReader::IsSupportedVideoMimeType(const nsACString& aMimeType) +{ + return mPlatform && (mPlatform->SupportsMimeType(aMimeType) || + PlatformDecoderModule::AgnosticMimeType(aMimeType)); +} + nsRefPtr MediaFormatReader::AsyncReadMetadata() { @@ -365,20 +379,33 @@ MediaFormatReader::EnsureDecodersCreated() MOZ_ASSERT(OnTaskQueue()); if (!mPlatform) { - mPlatform = new PDMFactory(); - NS_ENSURE_TRUE(mPlatform, false); if (IsEncrypted()) { #ifdef MOZ_EME + // We have encrypted audio or video. We'll need a CDM to decrypt and + // possibly decode this. Wait until we've received a CDM from the + // JavaScript player app. Note: we still go through the motions here + // even if EME is disabled, so that if script tries and fails to create + // a CDM, we can detect that and notify chrome and show some UI + // explaining that we failed due to EME being disabled. MOZ_ASSERT(mCDMProxy); - mPlatform->SetCDMProxy(mCDMProxy); + mPlatform = PlatformDecoderModule::CreateCDMWrapper(mCDMProxy); + NS_ENSURE_TRUE(mPlatform, false); #else // EME not supported. return false; #endif + } else { + mPlatform = PlatformDecoderModule::Create(); + NS_ENSURE_TRUE(mPlatform, false); } } + MOZ_ASSERT(mPlatform); + if (HasAudio() && !mAudio.mDecoder) { + NS_ENSURE_TRUE(IsSupportedAudioMimeType(mInfo.mAudio.mMimeType), + false); + mAudio.mDecoderInitialized = false; mAudio.mDecoder = mPlatform->CreateDecoder(mAudio.mInfo ? @@ -390,6 +417,9 @@ MediaFormatReader::EnsureDecodersCreated() } if (HasVideo() && !mVideo.mDecoder) { + NS_ENSURE_TRUE(IsSupportedVideoMimeType(mInfo.mVideo.mMimeType), + false); + mVideo.mDecoderInitialized = false; // Decoders use the layers backend to decide if they can use hardware decoding, // so specify LAYERS_NONE if we want to forcibly disable it. diff --git a/dom/media/MediaFormatReader.h b/dom/media/MediaFormatReader.h index 85951ab12df6..935648091b5c 100644 --- a/dom/media/MediaFormatReader.h +++ b/dom/media/MediaFormatReader.h @@ -13,7 +13,7 @@ #include "MediaDataDemuxer.h" #include "MediaDecoderReader.h" -#include "PDMFactory.h" +#include "PlatformDecoderModule.h" namespace mozilla { @@ -147,13 +147,15 @@ private: void Error(TrackType aTrack); void Flush(TrackType aTrack); void DrainComplete(TrackType aTrack); + bool IsSupportedAudioMimeType(const nsACString& aMimeType); + bool IsSupportedVideoMimeType(const nsACString& aMimeType); bool ShouldSkip(bool aSkipToNextKeyframe, media::TimeUnit aTimeThreshold); size_t SizeOfQueue(TrackType aTrack); nsRefPtr mDemuxer; - nsRefPtr mPlatform; + nsRefPtr mPlatform; class DecoderCallback : public MediaDataDecoderCallback { public: diff --git a/dom/media/fmp4/MP4Decoder.cpp b/dom/media/fmp4/MP4Decoder.cpp index e92be5c3d630..bf15839327bf 100644 --- a/dom/media/fmp4/MP4Decoder.cpp +++ b/dom/media/fmp4/MP4Decoder.cpp @@ -27,7 +27,9 @@ #endif #include "mozilla/layers/LayersTypes.h" -#include "PDMFactory.h" +#ifdef MOZ_FFMPEG +#include "FFmpegRuntimeLinker.h" +#endif namespace mozilla { @@ -147,8 +149,11 @@ MP4Decoder::CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs, } // Verify that we have a PDM that supports the whitelisted types. - PDMFactory::Init(); - nsRefPtr platform = new PDMFactory(); + PlatformDecoderModule::Init(); + nsRefPtr platform = PlatformDecoderModule::Create(); + if (!platform) { + return false; + } for (const nsCString& codecMime : codecMimes) { if (!platform->SupportsMimeType(codecMime)) { return false; @@ -173,11 +178,79 @@ MP4Decoder::CanHandleMediaType(const nsAString& aContentType) return CanHandleMediaType(NS_ConvertUTF16toUTF8(mimeType), codecs); } +static bool +IsFFmpegAvailable() +{ +#ifndef MOZ_FFMPEG + return false; +#else + PlatformDecoderModule::Init(); + nsRefPtr m = FFmpegRuntimeLinker::CreateDecoderModule(); + return !!m; +#endif +} + +static bool +IsAppleAvailable() +{ +#ifndef MOZ_APPLEMEDIA + // Not the right platform. + return false; +#else + return Preferences::GetBool("media.apple.mp4.enabled", false); +#endif +} + +static bool +IsAndroidAvailable() +{ +#ifndef MOZ_WIDGET_ANDROID + return false; +#else + // We need android.media.MediaCodec which exists in API level 16 and higher. + return AndroidBridge::Bridge() && (AndroidBridge::Bridge()->GetAPIVersion() >= 16); +#endif +} + +static bool +IsGonkMP4DecoderAvailable() +{ +#ifndef MOZ_GONK_MEDIACODEC + return false; +#else + return Preferences::GetBool("media.fragmented-mp4.gonk.enabled", false); +#endif +} + +static bool +IsGMPDecoderAvailable() +{ + return Preferences::GetBool("media.fragmented-mp4.gmp.enabled", false); +} + +static bool +HavePlatformMPEGDecoders() +{ + return Preferences::GetBool("media.fragmented-mp4.use-blank-decoder") || +#ifdef XP_WIN + // We have H.264/AAC platform decoders on Windows Vista and up. + IsVistaOrLater() || +#endif + IsAndroidAvailable() || + IsFFmpegAvailable() || + IsAppleAvailable() || + IsGonkMP4DecoderAvailable() || + IsGMPDecoderAvailable() || + // TODO: Other platforms... + false; +} + /* static */ bool MP4Decoder::IsEnabled() { - return Preferences::GetBool("media.fragmented-mp4.enabled"); + return Preferences::GetBool("media.fragmented-mp4.enabled") && + HavePlatformMPEGDecoders(); } static const uint8_t sTestH264ExtraData[] = { @@ -201,11 +274,18 @@ CreateTestH264Decoder(layers::LayersBackend aBackend, aConfig.mExtraData->AppendElements(sTestH264ExtraData, MOZ_ARRAY_LENGTH(sTestH264ExtraData)); - PDMFactory::Init(); + PlatformDecoderModule::Init(); + + nsRefPtr platform = PlatformDecoderModule::Create(); + if (!platform || !platform->SupportsMimeType(NS_LITERAL_CSTRING("video/mp4"))) { + return nullptr; + } - nsRefPtr platform = new PDMFactory(); nsRefPtr decoder( platform->CreateDecoder(aConfig, nullptr, nullptr, aBackend, nullptr)); + if (!decoder) { + return nullptr; + } return decoder.forget(); } @@ -220,8 +300,93 @@ MP4Decoder::IsVideoAccelerated(layers::LayersBackend aBackend, nsACString& aFail return false; } bool result = decoder->IsHardwareAccelerated(aFailureReason); - decoder->Shutdown(); return result; } +/* static */ bool +MP4Decoder::CanCreateH264Decoder() +{ +#ifdef XP_WIN + static bool haveCachedResult = false; + static bool result = false; + if (haveCachedResult) { + return result; + } + VideoInfo config; + nsRefPtr decoder( + CreateTestH264Decoder(layers::LayersBackend::LAYERS_BASIC, config)); + if (decoder) { + decoder->Shutdown(); + result = true; + } + haveCachedResult = true; + return result; +#else + return IsEnabled(); +#endif +} + +#ifdef XP_WIN +static already_AddRefed +CreateTestAACDecoder(AudioInfo& aConfig) +{ + PlatformDecoderModule::Init(); + + nsRefPtr platform = PlatformDecoderModule::Create(); + if (!platform || !platform->SupportsMimeType(NS_LITERAL_CSTRING("audio/mp4a-latm"))) { + return nullptr; + } + + nsRefPtr decoder( + platform->CreateDecoder(aConfig, nullptr, nullptr)); + if (!decoder) { + return nullptr; + } + + return decoder.forget(); +} + +// bipbop.mp4's extradata/config... +static const uint8_t sTestAACExtraData[] = { + 0x03, 0x80, 0x80, 0x80, 0x22, 0x00, 0x02, 0x00, 0x04, 0x80, + 0x80, 0x80, 0x14, 0x40, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x51, 0x00, 0x00, 0x11, 0x51, 0x05, 0x80, 0x80, 0x80, + 0x02, 0x13, 0x90, 0x06, 0x80, 0x80, 0x80, 0x01, 0x02 +}; + +static const uint8_t sTestAACConfig[] = { 0x13, 0x90 }; + +#endif // XP_WIN + +/* static */ bool +MP4Decoder::CanCreateAACDecoder() +{ +#ifdef XP_WIN + static bool haveCachedResult = false; + static bool result = false; + if (haveCachedResult) { + return result; + } + AudioInfo config; + config.mMimeType = "audio/mp4a-latm"; + config.mRate = 22050; + config.mChannels = 2; + config.mBitDepth = 16; + config.mProfile = 2; + config.mExtendedProfile = 2; + config.mCodecSpecificConfig->AppendElements(sTestAACConfig, + MOZ_ARRAY_LENGTH(sTestAACConfig)); + config.mExtraData->AppendElements(sTestAACExtraData, + MOZ_ARRAY_LENGTH(sTestAACExtraData)); + nsRefPtr decoder(CreateTestAACDecoder(config)); + if (decoder) { + result = true; + } + haveCachedResult = true; + return result; +#else + return IsEnabled(); +#endif +} + } // namespace mozilla diff --git a/dom/media/fmp4/MP4Decoder.h b/dom/media/fmp4/MP4Decoder.h index f207838949eb..aceec851aec9 100644 --- a/dom/media/fmp4/MP4Decoder.h +++ b/dom/media/fmp4/MP4Decoder.h @@ -38,6 +38,8 @@ public: static bool IsEnabled(); static bool IsVideoAccelerated(layers::LayersBackend aBackend, nsACString& aReason); + static bool CanCreateAACDecoder(); + static bool CanCreateH264Decoder(); }; } // namespace mozilla diff --git a/dom/media/mediasource/test/mochitest.ini b/dom/media/mediasource/test/mochitest.ini index 2d990ce0b9b7..0005ff4e41b6 100644 --- a/dom/media/mediasource/test/mochitest.ini +++ b/dom/media/mediasource/test/mochitest.ini @@ -78,8 +78,6 @@ skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+ [test_SeekTwice_mp4.html] skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+ -[test_Sequence_mp4.html] -skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+ [test_SetModeThrows.html] [test_SplitAppendDelay.html] [test_SplitAppendDelay_mp4.html] diff --git a/dom/media/mediasource/test/test_Sequence_mp4.html b/dom/media/mediasource/test/test_Sequence_mp4.html deleted file mode 100644 index f0542438d9a1..000000000000 --- a/dom/media/mediasource/test/test_Sequence_mp4.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - MSE: Don't get stuck buffering for too long when we have frames to show - - - - - -

-
- - diff --git a/dom/media/platforms/PDMFactory.cpp b/dom/media/platforms/PDMFactory.cpp deleted file mode 100644 index 450f8f521222..000000000000 --- a/dom/media/platforms/PDMFactory.cpp +++ /dev/null @@ -1,275 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 "PDMFactory.h" - -#ifdef XP_WIN -#include "WMFDecoderModule.h" -#endif -#ifdef MOZ_FFMPEG -#include "FFmpegRuntimeLinker.h" -#endif -#ifdef MOZ_APPLEMEDIA -#include "AppleDecoderModule.h" -#endif -#ifdef MOZ_GONK_MEDIACODEC -#include "GonkDecoderModule.h" -#endif -#ifdef MOZ_WIDGET_ANDROID -#include "AndroidDecoderModule.h" -#endif -#include "GMPDecoderModule.h" - -#include "mozilla/Preferences.h" -#include "mozilla/TaskQueue.h" - -#include "mozilla/SharedThreadPool.h" - -#include "MediaInfo.h" -#include "FuzzingWrapper.h" -#include "H264Converter.h" - -#include "AgnosticDecoderModule.h" - -#ifdef MOZ_EME -#include "EMEDecoderModule.h" -#include "mozilla/CDMProxy.h" -#endif - -namespace mozilla { - -extern already_AddRefed CreateAgnosticDecoderModule(); -extern already_AddRefed CreateBlankDecoderModule(); - -bool PDMFactory::sUseBlankDecoder = false; -bool PDMFactory::sGonkDecoderEnabled = false; -bool PDMFactory::sAndroidMCDecoderEnabled = false; -bool PDMFactory::sAndroidMCDecoderPreferred = false; -bool PDMFactory::sGMPDecoderEnabled = false; -bool PDMFactory::sEnableFuzzingWrapper = false; -uint32_t PDMFactory::sVideoOutputMinimumInterval_ms = 0; -bool PDMFactory::sDontDelayInputExhausted = false; - -/* static */ -void -PDMFactory::Init() -{ - MOZ_ASSERT(NS_IsMainThread()); - static bool alreadyInitialized = false; - if (alreadyInitialized) { - return; - } - alreadyInitialized = true; - - Preferences::AddBoolVarCache(&sUseBlankDecoder, - "media.fragmented-mp4.use-blank-decoder"); -#ifdef MOZ_GONK_MEDIACODEC - Preferences::AddBoolVarCache(&sGonkDecoderEnabled, - "media.fragmented-mp4.gonk.enabled", false); -#endif -#ifdef MOZ_WIDGET_ANDROID - Preferences::AddBoolVarCache(&sAndroidMCDecoderEnabled, - "media.fragmented-mp4.android-media-codec.enabled", false); - Preferences::AddBoolVarCache(&sAndroidMCDecoderPreferred, - "media.fragmented-mp4.android-media-codec.preferred", false); -#endif - - Preferences::AddBoolVarCache(&sGMPDecoderEnabled, - "media.fragmented-mp4.gmp.enabled", false); - - Preferences::AddBoolVarCache(&sEnableFuzzingWrapper, - "media.decoder.fuzzing.enabled", false); - Preferences::AddUintVarCache(&sVideoOutputMinimumInterval_ms, - "media.decoder.fuzzing.video-output-minimum-interval-ms", 0); - Preferences::AddBoolVarCache(&sDontDelayInputExhausted, - "media.decoder.fuzzing.dont-delay-inputexhausted", false); - -#ifdef XP_WIN - WMFDecoderModule::Init(); -#endif -#ifdef MOZ_APPLEMEDIA - AppleDecoderModule::Init(); -#endif -#ifdef MOZ_FFMPEG - FFmpegRuntimeLinker::Link(); -#endif -} - -PDMFactory::PDMFactory() -{ - CreatePDMs(); -} - -PDMFactory::~PDMFactory() -{ -} - -already_AddRefed -PDMFactory::CreateDecoder(const TrackInfo& aConfig, - FlushableTaskQueue* aTaskQueue, - MediaDataDecoderCallback* aCallback, - layers::LayersBackend aLayersBackend, - layers::ImageContainer* aImageContainer) -{ - nsRefPtr current = (mEMEPDM && aConfig.mCrypto.mValid) - ? mEMEPDM : GetDecoder(aConfig.mMimeType); - - if (!current) { - return nullptr; - } - nsRefPtr m; - - if (aConfig.GetAsAudioInfo()) { - m = current->CreateAudioDecoder(*aConfig.GetAsAudioInfo(), - aTaskQueue, - aCallback); - return m.forget(); - } - - if (!aConfig.GetAsVideoInfo()) { - return nullptr; - } - - MediaDataDecoderCallback* callback = aCallback; - nsRefPtr callbackWrapper; - if (sEnableFuzzingWrapper) { - callbackWrapper = new DecoderCallbackFuzzingWrapper(aCallback); - callbackWrapper->SetVideoOutputMinimumInterval( - TimeDuration::FromMilliseconds(sVideoOutputMinimumInterval_ms)); - callbackWrapper->SetDontDelayInputExhausted(sDontDelayInputExhausted); - callback = callbackWrapper.get(); - } - - if (H264Converter::IsH264(aConfig)) { - nsRefPtr h - = new H264Converter(current, - *aConfig.GetAsVideoInfo(), - aLayersBackend, - aImageContainer, - aTaskQueue, - callback); - const nsresult rv = h->GetLastError(); - if (NS_SUCCEEDED(rv) || rv == NS_ERROR_NOT_INITIALIZED) { - // The H264Converter either successfully created the wrapped decoder, - // or there wasn't enough AVCC data to do so. Otherwise, there was some - // problem, for example WMF DLLs were missing. - m = h.forget(); - } - } else { - m = current->CreateVideoDecoder(*aConfig.GetAsVideoInfo(), - aLayersBackend, - aImageContainer, - aTaskQueue, - callback); - } - - if (callbackWrapper && m) { - m = new DecoderFuzzingWrapper(m.forget(), callbackWrapper.forget()); - } - - return m.forget(); -} - -bool -PDMFactory::SupportsMimeType(const nsACString& aMimeType) -{ - if (mEMEPDM) { - return mEMEPDM->SupportsMimeType(aMimeType); - } - nsRefPtr current = GetDecoder(aMimeType); - return !!current; -} - -void -PDMFactory::CreatePDMs() -{ - nsRefPtr m; - - if (sGMPDecoderEnabled) { - m = new GMPDecoderModule(); - StartupPDM(m); - } -#ifdef MOZ_WIDGET_ANDROID - if(sAndroidMCDecoderPreferred && sAndroidMCDecoderEnabled) { - m = new AndroidDecoderModule(); - StartupPDM(m); - } -#endif -#ifdef XP_WIN - m = new WMFDecoderModule(); - StartupPDM(m); -#endif -#ifdef MOZ_FFMPEG - m = FFmpegRuntimeLinker::CreateDecoderModule(); - StartupPDM(m); -#endif -#ifdef MOZ_APPLEMEDIA - m = new AppleDecoderModule(); - StartupPDM(m); -#endif -#ifdef MOZ_GONK_MEDIACODEC - if (sGonkDecoderEnabled) { - m = new GonkDecoderModule(); - StartupPDM(m); - } -#endif -#ifdef MOZ_WIDGET_ANDROID - if(sAndroidMCDecoderEnabled){ - m = new AndroidDecoderModule(); - StartupPDM(m); - } -#endif - - m = new AgnosticDecoderModule(); - StartupPDM(m); - - if (sUseBlankDecoder) { - m = CreateBlankDecoderModule(); - StartupPDM(m); - } -} - -bool -PDMFactory::StartupPDM(PlatformDecoderModule* aPDM) -{ - if (aPDM && NS_SUCCEEDED(aPDM->Startup())) { - mCurrentPDMs.AppendElement(aPDM); - return true; - } - return false; -} - -already_AddRefed -PDMFactory::GetDecoder(const nsACString& aMimeType) -{ - nsRefPtr pdm; - for (auto& current : mCurrentPDMs) { - if (current->SupportsMimeType(aMimeType)) { - pdm = current; - break; - } - } - return pdm.forget(); -} - -#ifdef MOZ_EME -void -PDMFactory::SetCDMProxy(CDMProxy* aProxy) -{ - bool cdmDecodesAudio; - bool cdmDecodesVideo; - { - CDMCaps::AutoLock caps(aProxy->Capabilites()); - cdmDecodesAudio = caps.CanDecryptAndDecodeAudio(); - cdmDecodesVideo = caps.CanDecryptAndDecodeVideo(); - } - - nsRefPtr m = new PDMFactory(); - mEMEPDM = new EMEDecoderModule(aProxy, m, cdmDecodesAudio, cdmDecodesVideo); -} -#endif - -} // namespace mozilla diff --git a/dom/media/platforms/PDMFactory.h b/dom/media/platforms/PDMFactory.h deleted file mode 100644 index 7accf3776403..000000000000 --- a/dom/media/platforms/PDMFactory.h +++ /dev/null @@ -1,73 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ - -#if !defined(PDMFactory_h_) -#define PDMFactory_h_ - -#include "PlatformDecoderModule.h" - -class CDMProxy; - -namespace mozilla { - -class PDMFactory final { -public: - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PDMFactory) - - PDMFactory(); - - // Call on the main thread to initialize the static state - // needed by Create(). - static void Init(); - - // Factory method that creates the appropriate PlatformDecoderModule for - // the platform we're running on. Caller is responsible for deleting this - // instance. It's expected that there will be multiple - // PlatformDecoderModules alive at the same time. - // This is called on the decode task queue. - already_AddRefed - CreateDecoder(const TrackInfo& aConfig, - FlushableTaskQueue* aTaskQueue, - MediaDataDecoderCallback* aCallback, - layers::LayersBackend aLayersBackend = layers::LayersBackend::LAYERS_NONE, - layers::ImageContainer* aImageContainer = nullptr); - - bool SupportsMimeType(const nsACString& aMimeType); - -#ifdef MOZ_EME - // Creates a PlatformDecoderModule that uses a CDMProxy to decrypt or - // decrypt-and-decode EME encrypted content. If the CDM only decrypts and - // does not decode, we create a PDM and use that to create MediaDataDecoders - // that we use on on aTaskQueue to decode the decrypted stream. - // This is called on the decode task queue. - void SetCDMProxy(CDMProxy* aProxy); -#endif - -private: - virtual ~PDMFactory(); - void CreatePDMs(); - // Startup the provided PDM and add it to our list if successful. - bool StartupPDM(PlatformDecoderModule* aPDM); - // Returns the first PDM in our list supporting the mimetype. - already_AddRefed GetDecoder(const nsACString& aMimeType); - - // Caches pref media.fragmented-mp4.use-blank-decoder - static bool sUseBlankDecoder; - static bool sGonkDecoderEnabled; - static bool sAndroidMCDecoderPreferred; - static bool sAndroidMCDecoderEnabled; - static bool sGMPDecoderEnabled; - static bool sEnableFuzzingWrapper; - static uint32_t sVideoOutputMinimumInterval_ms; - static bool sDontDelayInputExhausted; - - nsTArray> mCurrentPDMs; - nsRefPtr mEMEPDM; -}; - -} // namespace mozilla - -#endif /* PDMFactory_h_ */ diff --git a/dom/media/platforms/PlatformDecoderModule.cpp b/dom/media/platforms/PlatformDecoderModule.cpp index bb02119700bc..70294c9c1a0b 100644 --- a/dom/media/platforms/PlatformDecoderModule.cpp +++ b/dom/media/platforms/PlatformDecoderModule.cpp @@ -6,6 +6,40 @@ #include "PlatformDecoderModule.h" +#ifdef XP_WIN +#include "WMFDecoderModule.h" +#endif +#ifdef MOZ_FFMPEG +#include "FFmpegRuntimeLinker.h" +#endif +#ifdef MOZ_APPLEMEDIA +#include "AppleDecoderModule.h" +#endif +#ifdef MOZ_GONK_MEDIACODEC +#include "GonkDecoderModule.h" +#endif +#ifdef MOZ_WIDGET_ANDROID +#include "AndroidDecoderModule.h" +#endif +#include "GMPDecoderModule.h" + +#include "mozilla/Preferences.h" +#include "mozilla/TaskQueue.h" + +#ifdef MOZ_EME +#include "EMEDecoderModule.h" +#include "mozilla/CDMProxy.h" +#endif +#include "mozilla/SharedThreadPool.h" + +#include "MediaInfo.h" +#include "FuzzingWrapper.h" +#include "H264Converter.h" + +#include "OpusDecoder.h" +#include "VorbisDecoder.h" +#include "VPXDecoder.h" + PRLogModuleInfo* GetPDMLog() { static PRLogModuleInfo* log = nullptr; if (!log) { @@ -13,3 +47,249 @@ PRLogModuleInfo* GetPDMLog() { } return log; } + +namespace mozilla { + +extern already_AddRefed CreateAgnosticDecoderModule(); +extern already_AddRefed CreateBlankDecoderModule(); + +bool PlatformDecoderModule::sUseBlankDecoder = false; +bool PlatformDecoderModule::sFFmpegDecoderEnabled = false; +bool PlatformDecoderModule::sGonkDecoderEnabled = false; +bool PlatformDecoderModule::sAndroidMCDecoderEnabled = false; +bool PlatformDecoderModule::sAndroidMCDecoderPreferred = false; +bool PlatformDecoderModule::sGMPDecoderEnabled = false; +bool PlatformDecoderModule::sEnableFuzzingWrapper = false; +uint32_t PlatformDecoderModule::sVideoOutputMinimumInterval_ms = 0; +bool PlatformDecoderModule::sDontDelayInputExhausted = false; + +/* static */ +void +PlatformDecoderModule::Init() +{ + MOZ_ASSERT(NS_IsMainThread()); + static bool alreadyInitialized = false; + if (alreadyInitialized) { + return; + } + alreadyInitialized = true; + + Preferences::AddBoolVarCache(&sUseBlankDecoder, + "media.fragmented-mp4.use-blank-decoder"); + Preferences::AddBoolVarCache(&sFFmpegDecoderEnabled, + "media.fragmented-mp4.ffmpeg.enabled", false); + +#ifdef MOZ_GONK_MEDIACODEC + Preferences::AddBoolVarCache(&sGonkDecoderEnabled, + "media.fragmented-mp4.gonk.enabled", false); +#endif +#ifdef MOZ_WIDGET_ANDROID + Preferences::AddBoolVarCache(&sAndroidMCDecoderEnabled, + "media.fragmented-mp4.android-media-codec.enabled", false); + Preferences::AddBoolVarCache(&sAndroidMCDecoderPreferred, + "media.fragmented-mp4.android-media-codec.preferred", false); +#endif + + Preferences::AddBoolVarCache(&sGMPDecoderEnabled, + "media.fragmented-mp4.gmp.enabled", false); + + Preferences::AddBoolVarCache(&sEnableFuzzingWrapper, + "media.decoder.fuzzing.enabled", false); + Preferences::AddUintVarCache(&sVideoOutputMinimumInterval_ms, + "media.decoder.fuzzing.video-output-minimum-interval-ms", 0); + Preferences::AddBoolVarCache(&sDontDelayInputExhausted, + "media.decoder.fuzzing.dont-delay-inputexhausted", false); + +#ifdef XP_WIN + WMFDecoderModule::Init(); +#endif +#ifdef MOZ_APPLEMEDIA + AppleDecoderModule::Init(); +#endif +#ifdef MOZ_FFMPEG + FFmpegRuntimeLinker::Link(); +#endif +} + +#ifdef MOZ_EME +/* static */ +already_AddRefed +PlatformDecoderModule::CreateCDMWrapper(CDMProxy* aProxy) +{ + bool cdmDecodesAudio; + bool cdmDecodesVideo; + { + CDMCaps::AutoLock caps(aProxy->Capabilites()); + cdmDecodesAudio = caps.CanDecryptAndDecodeAudio(); + cdmDecodesVideo = caps.CanDecryptAndDecodeVideo(); + } + + // We always create a default PDM in order to decode + // non-encrypted tracks. + nsRefPtr pdm = Create(); + if (!pdm) { + return nullptr; + } + + nsRefPtr emepdm( + new EMEDecoderModule(aProxy, pdm, cdmDecodesAudio, cdmDecodesVideo)); + return emepdm.forget(); +} +#endif + +/* static */ +already_AddRefed +PlatformDecoderModule::Create() +{ + // Note: This (usually) runs on the decode thread. + + nsRefPtr m(CreatePDM()); + + if (m && NS_SUCCEEDED(m->Startup())) { + return m.forget(); + } + return CreateAgnosticDecoderModule(); +} + +/* static */ +already_AddRefed +PlatformDecoderModule::CreatePDM() +{ + if (sGMPDecoderEnabled) { + nsRefPtr m(new GMPDecoderModule()); + return m.forget(); + } +#ifdef MOZ_WIDGET_ANDROID + if(sAndroidMCDecoderPreferred && sAndroidMCDecoderEnabled){ + nsRefPtr m(new AndroidDecoderModule()); + return m.forget(); + } +#endif + if (sUseBlankDecoder) { + return CreateBlankDecoderModule(); + } +#ifdef XP_WIN + nsRefPtr m(new WMFDecoderModule()); + return m.forget(); +#endif +#ifdef MOZ_FFMPEG + nsRefPtr mffmpeg = FFmpegRuntimeLinker::CreateDecoderModule(); + if (mffmpeg) { + return mffmpeg.forget(); + } +#endif +#ifdef MOZ_APPLEMEDIA + nsRefPtr m(new AppleDecoderModule()); + return m.forget(); +#endif +#ifdef MOZ_GONK_MEDIACODEC + if (sGonkDecoderEnabled) { + nsRefPtr m(new GonkDecoderModule()); + return m.forget(); + } +#endif +#ifdef MOZ_WIDGET_ANDROID + if(sAndroidMCDecoderEnabled){ + nsRefPtr m(new AndroidDecoderModule()); + return m.forget(); + } +#endif + return nullptr; +} + +already_AddRefed +PlatformDecoderModule::CreateDecoder(const TrackInfo& aConfig, + FlushableTaskQueue* aTaskQueue, + MediaDataDecoderCallback* aCallback, + layers::LayersBackend aLayersBackend, + layers::ImageContainer* aImageContainer) +{ + nsRefPtr m; + + bool hasPlatformDecoder = SupportsMimeType(aConfig.mMimeType); + + if (aConfig.GetAsAudioInfo()) { + if (!hasPlatformDecoder && VorbisDataDecoder::IsVorbis(aConfig.mMimeType)) { + m = new VorbisDataDecoder(*aConfig.GetAsAudioInfo(), + aTaskQueue, + aCallback); + } else if (!hasPlatformDecoder && OpusDataDecoder::IsOpus(aConfig.mMimeType)) { + m = new OpusDataDecoder(*aConfig.GetAsAudioInfo(), + aTaskQueue, + aCallback); + } else { + m = CreateAudioDecoder(*aConfig.GetAsAudioInfo(), + aTaskQueue, + aCallback); + } + return m.forget(); + } + + if (!aConfig.GetAsVideoInfo()) { + return nullptr; + } + + MediaDataDecoderCallback* callback = aCallback; + nsRefPtr callbackWrapper; + if (sEnableFuzzingWrapper) { + callbackWrapper = new DecoderCallbackFuzzingWrapper(aCallback); + callbackWrapper->SetVideoOutputMinimumInterval( + TimeDuration::FromMilliseconds(sVideoOutputMinimumInterval_ms)); + callbackWrapper->SetDontDelayInputExhausted(sDontDelayInputExhausted); + callback = callbackWrapper.get(); + } + + if (H264Converter::IsH264(aConfig)) { + nsRefPtr h + = new H264Converter(this, + *aConfig.GetAsVideoInfo(), + aLayersBackend, + aImageContainer, + aTaskQueue, + callback); + const nsresult rv = h->GetLastError(); + if (NS_SUCCEEDED(rv) || rv == NS_ERROR_NOT_INITIALIZED) { + // The H264Converter either successfully created the wrapped decoder, + // or there wasn't enough AVCC data to do so. Otherwise, there was some + // problem, for example WMF DLLs were missing. + m = h.forget(); + } + } else if (!hasPlatformDecoder && VPXDecoder::IsVPX(aConfig.mMimeType)) { + m = new VPXDecoder(*aConfig.GetAsVideoInfo(), + aImageContainer, + aTaskQueue, + callback); + } else { + m = CreateVideoDecoder(*aConfig.GetAsVideoInfo(), + aLayersBackend, + aImageContainer, + aTaskQueue, + callback); + } + + if (callbackWrapper && m) { + m = new DecoderFuzzingWrapper(m.forget(), callbackWrapper.forget()); + } + + return m.forget(); +} + +bool +PlatformDecoderModule::SupportsMimeType(const nsACString& aMimeType) +{ + return aMimeType.EqualsLiteral("audio/mp4a-latm") || + aMimeType.EqualsLiteral("video/mp4") || + aMimeType.EqualsLiteral("video/avc"); +} + +/* static */ +bool +PlatformDecoderModule::AgnosticMimeType(const nsACString& aMimeType) +{ + return VPXDecoder::IsVPX(aMimeType) || + OpusDataDecoder::IsOpus(aMimeType) || + VorbisDataDecoder::IsVorbis(aMimeType); +} + + +} // namespace mozilla diff --git a/dom/media/platforms/PlatformDecoderModule.h b/dom/media/platforms/PlatformDecoderModule.h index 2191814dc4b2..bd633f6b4e30 100644 --- a/dom/media/platforms/PlatformDecoderModule.h +++ b/dom/media/platforms/PlatformDecoderModule.h @@ -30,30 +30,74 @@ class MediaDataDecoderCallback; class FlushableTaskQueue; class CDMProxy; -// The PlatformDecoderModule interface is used by the MediaFormatReader to -// abstract access to decoders provided by various -// platforms. -// Each platform (Windows, MacOSX, Linux, B2G etc) must implement a -// PlatformDecoderModule to provide access to its decoders in order to get -// decompressed H.264/AAC from the MediaFormatReader. +// The PlatformDecoderModule interface is used by the MP4Reader to abstract +// access to the H264 and Audio (AAC/MP3) decoders provided by various platforms. +// It may be extended to support other codecs in future. Each platform (Windows, +// MacOSX, Linux, B2G etc) must implement a PlatformDecoderModule to provide +// access to its decoders in order to get decompressed H.264/AAC from the +// MP4Reader. // -// Decoding is asynchronous, and should be performed on the task queue +// Video decoding is asynchronous, and should be performed on the task queue // provided if the underlying platform isn't already exposing an async API. // +// Platforms that don't have a corresponding PlatformDecoderModule won't be +// able to play the H.264/AAC data output by the MP4Reader. In practice this +// means that we won't have fragmented MP4 supported in Media Source +// Extensions. +// // A cross-platform decoder module that discards input and produces "blank" // output samples exists for testing, and is created when the pref // "media.fragmented-mp4.use-blank-decoder" is true. - class PlatformDecoderModule { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PlatformDecoderModule) + // Call on the main thread to initialize the static state + // needed by Create(). + static void Init(); + + // Factory method that creates the appropriate PlatformDecoderModule for + // the platform we're running on. Caller is responsible for deleting this + // instance. It's expected that there will be multiple + // PlatformDecoderModules alive at the same time. There is one + // PlatformDecoderModule created per MP4Reader. + // This is called on the decode task queue. + static already_AddRefed Create(); + // As Create() but do not initialize the created PlatformDecoderModule. + static already_AddRefed CreatePDM(); + // Perform any per-instance initialization. // This is called on the decode task queue. virtual nsresult Startup() { return NS_OK; }; - // Indicates if the PlatformDecoderModule supports decoding of aMimeType. - virtual bool SupportsMimeType(const nsACString& aMimeType) = 0; +#ifdef MOZ_EME + // Creates a PlatformDecoderModule that uses a CDMProxy to decrypt or + // decrypt-and-decode EME encrypted content. If the CDM only decrypts and + // does not decode, we create a PDM and use that to create MediaDataDecoders + // that we use on on aTaskQueue to decode the decrypted stream. + // This is called on the decode task queue. + static already_AddRefed + CreateCDMWrapper(CDMProxy* aProxy); +#endif + + // Creates a decoder. + // See CreateVideoDecoder and CreateAudioDecoder for implementation details. + virtual already_AddRefed + CreateDecoder(const TrackInfo& aConfig, + FlushableTaskQueue* aTaskQueue, + MediaDataDecoderCallback* aCallback, + layers::LayersBackend aLayersBackend = layers::LayersBackend::LAYERS_NONE, + layers::ImageContainer* aImageContainer = nullptr); + + // An audio decoder module must support AAC by default. + // A video decoder must support H264 by default. + // If more codecs are to be supported, SupportsMimeType will have + // to be extended + virtual bool SupportsMimeType(const nsACString& aMimeType); + + // MimeType can be decoded with shipped decoders if no platform decoders exist + static bool AgnosticMimeType(const nsACString& aMimeType); + enum ConversionRequired { kNeedNone, @@ -66,13 +110,15 @@ public: // feeding it to MediaDataDecoder::Input. virtual ConversionRequired DecoderNeedsConversion(const TrackInfo& aConfig) const = 0; + virtual bool SupportsSharedDecoders(const VideoInfo& aConfig) const { + return !AgnosticMimeType(aConfig.mMimeType); + } + protected: PlatformDecoderModule() {} virtual ~PlatformDecoderModule() {} friend class H264Converter; - friend class PDMFactory; - // Creates a Video decoder. The layers backend is passed in so that // decoders can determine whether hardware accelerated decoding can be used. // Asynchronous decoding of video should be done in runnables dispatched @@ -105,11 +151,21 @@ protected: CreateAudioDecoder(const AudioInfo& aConfig, FlushableTaskQueue* aAudioTaskQueue, MediaDataDecoderCallback* aCallback) = 0; + + // Caches pref media.fragmented-mp4.use-blank-decoder + static bool sUseBlankDecoder; + static bool sFFmpegDecoderEnabled; + static bool sGonkDecoderEnabled; + static bool sAndroidMCDecoderPreferred; + static bool sAndroidMCDecoderEnabled; + static bool sGMPDecoderEnabled; + static bool sEnableFuzzingWrapper; + static uint32_t sVideoOutputMinimumInterval_ms; + static bool sDontDelayInputExhausted; }; // A callback used by MediaDataDecoder to return output/errors to the -// MediaFormatReader. -// Implementation is threadsafe, and can be called on any thread. +// MP4Reader. Implementation is threadsafe, and can be called on any thread. class MediaDataDecoderCallback { public: virtual ~MediaDataDecoderCallback() {} @@ -139,7 +195,7 @@ public: // // Unless otherwise noted, all functions are only called on the decode task // queue. An exception is the MediaDataDecoder in -// MediaFormatReader::IsVideoAccelerated() for which all calls (Init(), +// MP4Reader::IsVideoAccelerated() for which all calls (Init(), // IsHardwareAccelerated(), and Shutdown()) are from the main thread. // // Don't block inside these functions, unless it's explicitly noted that you @@ -167,7 +223,7 @@ public: // Initialize the decoder. The decoder should be ready to decode once // promise resolves. The decoder should do any initialization here, rather // than in its constructor or PlatformDecoderModule::Create*Decoder(), - // so that if the MediaFormatReader needs to shutdown during initialization, + // so that if the MP4Reader needs to shutdown during initialization, // it can call Shutdown() to cancel this operation. Any initialization // that requires blocking the calling thread in this function *must* // be done here so that it can be canceled by calling Shutdown()! @@ -182,7 +238,7 @@ public: // decoding resumes after the seek. // While the reader calls Flush(), it ignores all output sent to it; // it is safe (but pointless) to send output while Flush is called. - // The MediaFormatReader will not call Input() while it's calling Flush(). + // The MP4Reader will not call Input() while it's calling Flush(). virtual nsresult Flush() = 0; // Causes all complete samples in the pipeline that can be decoded to be @@ -190,7 +246,7 @@ public: // it drops the input samples. The decoder may be holding onto samples // that are required to decode samples that it expects to get in future. // This is called when the demuxer reaches end of stream. - // The MediaFormatReader will not call Input() while it's calling Drain(). + // The MP4Reader will not call Input() while it's calling Drain(). // This function is asynchronous. The MediaDataDecoder must call // MediaDataDecoderCallback::DrainComplete() once all remaining // samples have been output. diff --git a/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp b/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp deleted file mode 100644 index c877e80f392f..000000000000 --- a/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 "AgnosticDecoderModule.h" -#include "OpusDecoder.h" -#include "VorbisDecoder.h" -#include "VPXDecoder.h" - -namespace mozilla { - -bool -AgnosticDecoderModule::SupportsMimeType(const nsACString& aMimeType) -{ - return VPXDecoder::IsVPX(aMimeType) || - OpusDataDecoder::IsOpus(aMimeType) || - VorbisDataDecoder::IsVorbis(aMimeType); -} - -already_AddRefed -AgnosticDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig, - layers::LayersBackend aLayersBackend, - layers::ImageContainer* aImageContainer, - FlushableTaskQueue* aVideoTaskQueue, - MediaDataDecoderCallback* aCallback) -{ - nsRefPtr m; - - if (VPXDecoder::IsVPX(aConfig.mMimeType)) { - m = new VPXDecoder(*aConfig.GetAsVideoInfo(), - aImageContainer, - aVideoTaskQueue, - aCallback); - } - - return m.forget(); -} - -already_AddRefed -AgnosticDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig, - FlushableTaskQueue* aAudioTaskQueue, - MediaDataDecoderCallback* aCallback) -{ - nsRefPtr m; - - if (VorbisDataDecoder::IsVorbis(aConfig.mMimeType)) { - m = new VorbisDataDecoder(*aConfig.GetAsAudioInfo(), - aAudioTaskQueue, - aCallback); - } else if (OpusDataDecoder::IsOpus(aConfig.mMimeType)) { - m = new OpusDataDecoder(*aConfig.GetAsAudioInfo(), - aAudioTaskQueue, - aCallback); - } - - return m.forget(); -} - -} // namespace mozilla diff --git a/dom/media/platforms/agnostic/AgnosticDecoderModule.h b/dom/media/platforms/agnostic/AgnosticDecoderModule.h deleted file mode 100644 index 97cc23e799b4..000000000000 --- a/dom/media/platforms/agnostic/AgnosticDecoderModule.h +++ /dev/null @@ -1,39 +0,0 @@ -#if !defined(AgnosticDecoderModule_h_) -#define AgnosticDecoderModule_h_ - -#include "PlatformDecoderModule.h" - -namespace mozilla { - -class AgnosticDecoderModule : public PlatformDecoderModule { -public: - AgnosticDecoderModule() = default; - virtual ~AgnosticDecoderModule() = default; - - bool SupportsMimeType(const nsACString& aMimeType) override; - - ConversionRequired - DecoderNeedsConversion(const TrackInfo& aConfig) const override - { - return ConversionRequired::kNeedNone; - } - -protected: - // Decode thread. - already_AddRefed - CreateVideoDecoder(const VideoInfo& aConfig, - layers::LayersBackend aLayersBackend, - layers::ImageContainer* aImageContainer, - FlushableTaskQueue* aVideoTaskQueue, - MediaDataDecoderCallback* aCallback) override; - - // Decode thread. - already_AddRefed - CreateAudioDecoder(const AudioInfo& aConfig, - FlushableTaskQueue* aAudioTaskQueue, - MediaDataDecoderCallback* aCallback) override; -}; - -} // namespace mozilla - -#endif /* AgnosticDecoderModule_h_ */ diff --git a/dom/media/platforms/agnostic/BlankDecoderModule.cpp b/dom/media/platforms/agnostic/BlankDecoderModule.cpp index 5b6e788f2964..b6a77f6298bd 100644 --- a/dom/media/platforms/agnostic/BlankDecoderModule.cpp +++ b/dom/media/platforms/agnostic/BlankDecoderModule.cpp @@ -251,6 +251,11 @@ public: return true; } + bool + SupportsSharedDecoders(const VideoInfo& aConfig) const override { + return false; + } + ConversionRequired DecoderNeedsConversion(const TrackInfo& aConfig) const override { @@ -259,10 +264,27 @@ public: }; +class AgnosticDecoderModule : public BlankDecoderModule { +public: + + bool SupportsMimeType(const nsACString& aMimeType) override + { + // This module does not support any decoders itself, + // agnostic decoders are created in PlatformDecoderModule::CreateDecoder + return false; + } +}; + already_AddRefed CreateBlankDecoderModule() { nsRefPtr pdm = new BlankDecoderModule(); return pdm.forget(); } +already_AddRefed CreateAgnosticDecoderModule() +{ + nsRefPtr adm = new AgnosticDecoderModule(); + return adm.forget(); +} + } // namespace mozilla diff --git a/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp b/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp index bdf95e5632e9..a2fd57796f0b 100644 --- a/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp +++ b/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp @@ -191,7 +191,7 @@ EMEMediaDataDecoderProxy::Shutdown() } EMEDecoderModule::EMEDecoderModule(CDMProxy* aProxy, - PDMFactory* aPDM, + PlatformDecoderModule* aPDM, bool aCDMDecodesAudio, bool aCDMDecodesVideo) : mProxy(aProxy) @@ -230,9 +230,7 @@ EMEDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig, FlushableTaskQueue* aVideoTaskQueue, MediaDataDecoderCallback* aCallback) { - MOZ_ASSERT(aConfig.mCrypto.mValid); - - if (mCDMDecodesVideo) { + if (mCDMDecodesVideo && aConfig.mCrypto.mValid) { nsRefPtr wrapper = CreateDecoderWrapper(aCallback, mProxy, aVideoTaskQueue); wrapper->SetProxyTarget(new EMEVideoDecoder(mProxy, aConfig, @@ -254,6 +252,10 @@ EMEDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig, return nullptr; } + if (!aConfig.mCrypto.mValid) { + return decoder.forget(); + } + nsRefPtr emeDecoder(new EMEDecryptor(decoder, aCallback, mProxy, @@ -266,9 +268,7 @@ EMEDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig, FlushableTaskQueue* aAudioTaskQueue, MediaDataDecoderCallback* aCallback) { - MOZ_ASSERT(aConfig.mCrypto.mValid); - - if (mCDMDecodesAudio) { + if (mCDMDecodesAudio && aConfig.mCrypto.mValid) { nsRefPtr wrapper = CreateDecoderWrapper(aCallback, mProxy, aAudioTaskQueue); wrapper->SetProxyTarget(new EMEAudioDecoder(mProxy, aConfig, @@ -284,6 +284,10 @@ EMEDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig, return nullptr; } + if (!aConfig.mCrypto.mValid) { + return decoder.forget(); + } + nsRefPtr emeDecoder(new EMEDecryptor(decoder, aCallback, mProxy, diff --git a/dom/media/platforms/agnostic/eme/EMEDecoderModule.h b/dom/media/platforms/agnostic/eme/EMEDecoderModule.h index 42e01f0c564a..23740ecfeb1c 100644 --- a/dom/media/platforms/agnostic/eme/EMEDecoderModule.h +++ b/dom/media/platforms/agnostic/eme/EMEDecoderModule.h @@ -8,7 +8,6 @@ #define EMEDecoderModule_h_ #include "PlatformDecoderModule.h" -#include "PDMFactory.h" #include "gmp-decryption.h" namespace mozilla { @@ -20,13 +19,12 @@ private: public: EMEDecoderModule(CDMProxy* aProxy, - PDMFactory* aPDM, + PlatformDecoderModule* aPDM, bool aCDMDecodesAudio, bool aCDMDecodesVideo); virtual ~EMEDecoderModule(); -protected: // Decode thread. already_AddRefed CreateVideoDecoder(const VideoInfo& aConfig, @@ -44,23 +42,15 @@ protected: ConversionRequired DecoderNeedsConversion(const TrackInfo& aConfig) const override; - bool - SupportsMimeType(const nsACString& aMimeType) override - { - // TODO Properly. - return aMimeType.EqualsLiteral("audio/mp4a-latm") || - aMimeType.EqualsLiteral("video/mp4") || - aMimeType.EqualsLiteral("video/avc"); - } - private: nsRefPtr mProxy; // Will be null if CDM has decoding capability. - nsRefPtr mPDM; + nsRefPtr mPDM; // We run the PDM on its own task queue. nsRefPtr mTaskQueue; bool mCDMDecodesAudio; bool mCDMDecodesVideo; + }; } // namespace mozilla diff --git a/dom/media/platforms/agnostic/gmp/GMPDecoderModule.h b/dom/media/platforms/agnostic/gmp/GMPDecoderModule.h index 1a60997c96cc..990f8b804fcf 100644 --- a/dom/media/platforms/agnostic/gmp/GMPDecoderModule.h +++ b/dom/media/platforms/agnostic/gmp/GMPDecoderModule.h @@ -33,14 +33,6 @@ public: ConversionRequired DecoderNeedsConversion(const TrackInfo& aConfig) const override; - - bool - SupportsMimeType(const nsACString& aMimeType) override - { - // TODO properly. - return aMimeType.EqualsLiteral("audio/mp4a-latm") || - aMimeType.EqualsLiteral("video/avc"); - } }; } // namespace mozilla diff --git a/dom/media/platforms/apple/AppleDecoderModule.cpp b/dom/media/platforms/apple/AppleDecoderModule.cpp index 8e0b1d482c48..c9b82613e08d 100644 --- a/dom/media/platforms/apple/AppleDecoderModule.cpp +++ b/dom/media/platforms/apple/AppleDecoderModule.cpp @@ -110,9 +110,7 @@ bool AppleDecoderModule::SupportsMimeType(const nsACString& aMimeType) { return aMimeType.EqualsLiteral("audio/mpeg") || - aMimeType.EqualsLiteral("audio/mp4a-latm") || - aMimeType.EqualsLiteral("video/mp4") || - aMimeType.EqualsLiteral("video/avc"); + PlatformDecoderModule::SupportsMimeType(aMimeType); } PlatformDecoderModule::ConversionRequired diff --git a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp index 84e4c24f6add..6079c8673be4 100644 --- a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp @@ -70,16 +70,24 @@ ChoosePixelFormat(AVCodecContext* aCodecContext, const PixelFormat* aFormats) nsresult FFmpegDataDecoder::InitDecoder() { + StaticMutexAutoLock mon(sMonitor); + FFMPEG_LOG("Initialising FFmpeg decoder."); - AVCodec* codec = FindAVCodec(mCodecID); + if (!sFFmpegInitDone) { + avcodec_register_all(); +#ifdef DEBUG + av_log_set_level(AV_LOG_DEBUG); +#endif + sFFmpegInitDone = true; + } + + AVCodec* codec = avcodec_find_decoder(mCodecID); if (!codec) { NS_WARNING("Couldn't find ffmpeg decoder"); return NS_ERROR_FAILURE; } - StaticMutexAutoLock mon(sMonitor); - if (!(mCodecContext = avcodec_alloc_context3(codec))) { NS_WARNING("Couldn't init ffmpeg context"); return NS_ERROR_FAILURE; @@ -232,18 +240,4 @@ FFmpegDataDecoder::PrepareFrame() return mFrame; } -/* static */ AVCodec* -FFmpegDataDecoder::FindAVCodec(AVCodecID aCodec) -{ - StaticMutexAutoLock mon(sMonitor); - if (!sFFmpegInitDone) { - avcodec_register_all(); -#ifdef DEBUG - av_log_set_level(AV_LOG_DEBUG); -#endif - sFFmpegInitDone = true; - } - return avcodec_find_decoder(aCodec); -} - } // namespace mozilla diff --git a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.h b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.h index c8f98e0835ea..9b7cfb124839 100644 --- a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.h +++ b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.h @@ -36,8 +36,6 @@ public: nsresult Drain() override; nsresult Shutdown() override; - static AVCodec* FindAVCodec(AVCodecID aCodec); - protected: // Flush and Drain operation, always run virtual void ProcessFlush(); diff --git a/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h b/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h index ef9973d1ce2b..0e99695d205d 100644 --- a/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h +++ b/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h @@ -10,7 +10,6 @@ #include "PlatformDecoderModule.h" #include "FFmpegAudioDecoder.h" #include "FFmpegH264Decoder.h" -#include "FFmpegRuntimeLinker.h" namespace mozilla { @@ -24,7 +23,7 @@ public: { uint32_t major, minor; GetVersion(major, minor); - if (major < 54 && !FFmpegRuntimeLinker::sFFmpegDecoderEnabled) { + if (major < 54 && !sFFmpegDecoderEnabled) { return nullptr; } nsRefPtr pdm = new FFmpegDecoderModule(); @@ -69,13 +68,8 @@ public: bool SupportsMimeType(const nsACString& aMimeType) override { - AVCodecID audioCodec = FFmpegAudioDecoder::GetCodecId(aMimeType); - AVCodecID videoCodec = FFmpegH264Decoder::GetCodecId(aMimeType); - if (audioCodec == AV_CODEC_ID_NONE && videoCodec == AV_CODEC_ID_NONE) { - return false; - } - AVCodecID codec = audioCodec != AV_CODEC_ID_NONE ? audioCodec : videoCodec; - return !!FFmpegDataDecoder::FindAVCodec(codec); + return FFmpegAudioDecoder::GetCodecId(aMimeType) != AV_CODEC_ID_NONE || + FFmpegH264Decoder::GetCodecId(aMimeType) != AV_CODEC_ID_NONE; } ConversionRequired diff --git a/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp b/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp index a60851de21cd..ca3d9fea75e0 100644 --- a/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp @@ -9,15 +9,12 @@ #include "FFmpegRuntimeLinker.h" #include "mozilla/ArrayUtils.h" #include "FFmpegLog.h" -#include "mozilla/Preferences.h" #define NUM_ELEMENTS(X) (sizeof(X) / sizeof((X)[0])) namespace mozilla { -bool FFmpegRuntimeLinker::sFFmpegDecoderEnabled = false; - FFmpegRuntimeLinker::LinkStatus FFmpegRuntimeLinker::sLinkStatus = LinkStatus_INIT; @@ -62,9 +59,6 @@ FFmpegRuntimeLinker::Link() return sLinkStatus == LinkStatus_SUCCEEDED; } - Preferences::AddBoolVarCache(&sFFmpegDecoderEnabled, - "media.fragmented-mp4.ffmpeg.enabled", false); - MOZ_ASSERT(NS_IsMainThread()); for (size_t i = 0; i < ArrayLength(sLibs); i++) { diff --git a/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.h b/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.h index 5e098dfa1f10..68e42f15ce64 100644 --- a/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.h +++ b/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.h @@ -22,8 +22,6 @@ public: static void Unlink(); static already_AddRefed CreateDecoderModule(); - static bool sFFmpegDecoderEnabled; - private: static void* sLinkedLib; static const AvCodecLib* sLib; diff --git a/dom/media/platforms/moz.build b/dom/media/platforms/moz.build index 58f24494fd04..66e17091aa07 100644 --- a/dom/media/platforms/moz.build +++ b/dom/media/platforms/moz.build @@ -5,23 +5,19 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. EXPORTS += [ - 'agnostic/AgnosticDecoderModule.h', 'agnostic/OpusDecoder.h', 'agnostic/VorbisDecoder.h', 'agnostic/VPXDecoder.h', - 'PDMFactory.h', 'PlatformDecoderModule.h', 'wrappers/FuzzingWrapper.h', 'wrappers/H264Converter.h' ] UNIFIED_SOURCES += [ - 'agnostic/AgnosticDecoderModule.cpp', 'agnostic/BlankDecoderModule.cpp', 'agnostic/OpusDecoder.cpp', 'agnostic/VorbisDecoder.cpp', 'agnostic/VPXDecoder.cpp', - 'PDMFactory.cpp', 'PlatformDecoderModule.cpp', 'wrappers/FuzzingWrapper.cpp', 'wrappers/H264Converter.cpp' diff --git a/dom/media/webm/AudioDecoder.cpp b/dom/media/webm/AudioDecoder.cpp index f23de9bad704..288aeadd752a 100644 --- a/dom/media/webm/AudioDecoder.cpp +++ b/dom/media/webm/AudioDecoder.cpp @@ -47,7 +47,7 @@ ogg_packet InitOggPacket(const unsigned char* aData, size_t aLength, class VorbisDecoder : public WebMAudioDecoder { public: - nsresult Init() override; + nsRefPtr Init() override; void Shutdown() override; nsresult ResetDecode() override; nsresult DecodeHeader(const unsigned char* aData, size_t aLength) override; @@ -94,14 +94,14 @@ VorbisDecoder::Shutdown() mReader = nullptr; } -nsresult +nsRefPtr VorbisDecoder::Init() { vorbis_info_init(&mVorbisInfo); vorbis_comment_init(&mVorbisComment); PodZero(&mVorbisDsp); PodZero(&mVorbisBlock); - return NS_OK; + return InitPromise::CreateAndResolve(TrackType::kAudioTrack, __func__); } nsresult @@ -229,7 +229,7 @@ VorbisDecoder::Decode(const unsigned char* aData, size_t aLength, class OpusDecoder : public WebMAudioDecoder { public: - nsresult Init() override; + nsRefPtr Init() override; void Shutdown() override; nsresult ResetDecode() override; nsresult DecodeHeader(const unsigned char* aData, size_t aLength) override; @@ -277,10 +277,10 @@ OpusDecoder::Shutdown() mReader = nullptr; } -nsresult +nsRefPtr OpusDecoder::Init() { - return NS_OK; + return InitPromise::CreateAndResolve(TrackType::kAudioTrack, __func__); } nsresult diff --git a/dom/media/webm/IntelWebMVideoDecoder.cpp b/dom/media/webm/IntelWebMVideoDecoder.cpp new file mode 100644 index 000000000000..e0bf886219a1 --- /dev/null +++ b/dom/media/webm/IntelWebMVideoDecoder.cpp @@ -0,0 +1,443 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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 "IntelWebMVideoDecoder.h" + +#include "mozilla/TaskQueue.h" + +#include "gfx2DGlue.h" +#include "Layers.h" +#include "MediaResource.h" +#include "mozilla/dom/HTMLMediaElement.h" +#include "nsError.h" +#include "mozilla/SharedThreadPool.h" +#include "VorbisUtils.h" +#include "nestegg/nestegg.h" + +#define VPX_DONT_DEFINE_STDINT_TYPES +#include "vpx/vp8dx.h" +#include "vpx/vpx_decoder.h" + +#undef LOG +extern PRLogModuleInfo* GetPDMLog(); +#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__)) + +namespace mozilla { + +using layers::Image; +using layers::LayerManager; +using layers::LayersBackend; + +class VP8Sample : public MediaRawData +{ +public: + VP8Sample(int64_t aTimestamp, + int64_t aDuration, + int64_t aByteOffset, + uint8_t* aData, + size_t aSize, + bool aSyncPoint) + : MediaRawData(aData, aSize) + { + mTimecode = -1; + mTime = aTimestamp; + mDuration = aDuration; + mOffset = aByteOffset; + mKeyframe = aSyncPoint; + } +}; + +IntelWebMVideoDecoder::IntelWebMVideoDecoder(WebMReader* aReader) + : WebMVideoDecoder() + , mReader(aReader) + , mMonitor("IntelWebMVideoDecoder") + , mNumSamplesInput(0) + , mNumSamplesOutput(0) + , mDecodeAhead(2) + , mInputExhausted(false) + , mDrainComplete(false) + , mError(false) + , mEOS(false) + , mIsFlushing(false) +{ + MOZ_COUNT_CTOR(IntelWebMVideoDecoder); +} + +IntelWebMVideoDecoder::~IntelWebMVideoDecoder() +{ + MOZ_COUNT_DTOR(IntelWebMVideoDecoder); + Shutdown(); +} + +void +IntelWebMVideoDecoder::Shutdown() +{ + if (mMediaDataDecoder) { + Flush(); + mMediaDataDecoder->Shutdown(); + mMediaDataDecoder = nullptr; + } + + mTaskQueue = nullptr; + + mQueuedVideoSample = nullptr; + mReader = nullptr; +} + +/* static */ +WebMVideoDecoder* +IntelWebMVideoDecoder::Create(WebMReader* aReader) +{ + nsAutoPtr decoder(new IntelWebMVideoDecoder(aReader)); + + decoder->mTaskQueue = aReader->GetVideoTaskQueue(); + NS_ENSURE_TRUE(decoder->mTaskQueue, nullptr); + + return decoder.forget(); +} + +bool +IntelWebMVideoDecoder::IsSupportedVideoMimeType(const nsACString& aMimeType) +{ + return (aMimeType.EqualsLiteral("video/webm; codecs=vp8") || + aMimeType.EqualsLiteral("video/webm; codecs=vp9")) && + mPlatform->SupportsMimeType(aMimeType); +} + +nsRefPtr +IntelWebMVideoDecoder::Init(unsigned int aWidth, unsigned int aHeight) +{ + mPlatform = PlatformDecoderModule::Create(); + if (!mPlatform) { + return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__); + } + + mDecoderConfig = new VideoInfo(); + mDecoderConfig->mDuration = 0; + mDecoderConfig->mDisplay.width = aWidth; + mDecoderConfig->mDisplay.height = aHeight; + + switch (mReader->GetVideoCodec()) { + case NESTEGG_CODEC_VP8: + mDecoderConfig->mMimeType = "video/webm; codecs=vp8"; + break; + case NESTEGG_CODEC_VP9: + mDecoderConfig->mMimeType = "video/webm; codecs=vp9"; + break; + default: + return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__); + } + + const VideoInfo& video = *mDecoderConfig; + if (!IsSupportedVideoMimeType(video.mMimeType)) { + return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__); + } + mMediaDataDecoder = + mPlatform->CreateDecoder(video, + mTaskQueue, + this, + mReader->GetLayersBackendType(), + mReader->GetDecoder()->GetImageContainer()); + if (!mMediaDataDecoder) { + return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__); + } + + return mMediaDataDecoder->Init(); +} + +bool +IntelWebMVideoDecoder::Demux(nsRefPtr& aSample, bool* aEOS) +{ + nsRefPtr holder(mReader->NextPacket(WebMReader::VIDEO)); + if (!holder) { + return false; + } + + nestegg_packet* packet = holder->Packet(); + unsigned int track = 0; + int r = nestegg_packet_track(packet, &track); + if (r == -1) { + return false; + } + + unsigned int count = 0; + r = nestegg_packet_count(packet, &count); + if (r == -1) { + return false; + } + + if (count > 1) { + NS_WARNING("Packet contains more than one video frame"); + return false; + } + + int64_t tstamp = holder->Timestamp(); + + // The end time of this frame is the start time of the next frame. Fetch + // the timestamp of the next packet for this track. If we've reached the + // end of the resource, use the file's duration as the end time of this + // video frame. + int64_t next_tstamp = 0; + nsRefPtr next_holder(mReader->NextPacket(WebMReader::VIDEO)); + if (next_holder) { + next_tstamp = holder->Timestamp(); + mReader->PushVideoPacket(next_holder); + } else { + next_tstamp = tstamp; + next_tstamp += tstamp - mReader->GetLastVideoFrameTime(); + } + mReader->SetLastVideoFrameTime(tstamp); + + unsigned char* data; + size_t length; + r = nestegg_packet_data(packet, 0, &data, &length); + if (r == -1) { + return false; + } + + vpx_codec_stream_info_t si; + PodZero(&si); + si.sz = sizeof(si); + if (mReader->GetVideoCodec() == NESTEGG_CODEC_VP8) { + vpx_codec_peek_stream_info(vpx_codec_vp8_dx(), data, length, &si); + } else if (mReader->GetVideoCodec() == NESTEGG_CODEC_VP9) { + vpx_codec_peek_stream_info(vpx_codec_vp9_dx(), data, length, &si); + } + + MOZ_ASSERT(mPlatform && mMediaDataDecoder); + + aSample = new VP8Sample(tstamp, + next_tstamp - tstamp, + 0, + data, + length, + si.is_kf); + if (!aSample->Data()) { + return false; + } + + return true; +} + +bool +IntelWebMVideoDecoder::Decode() +{ + MOZ_ASSERT(mMediaDataDecoder); + + mMonitor.Lock(); + uint64_t prevNumFramesOutput = mNumSamplesOutput; + while (prevNumFramesOutput == mNumSamplesOutput) { + mMonitor.AssertCurrentThreadOwns(); + if (mError) { + // Decode error! + mMonitor.Unlock(); + return false; + } + while (prevNumFramesOutput == mNumSamplesOutput && + (mInputExhausted || + (mNumSamplesInput - mNumSamplesOutput) < mDecodeAhead) && + !mEOS) { + mMonitor.AssertCurrentThreadOwns(); + mMonitor.Unlock(); + nsRefPtr compressed(PopSample()); + if (!compressed) { + // EOS, or error. Let the state machine know there are no more + // frames coming. + LOG("Draining Video"); + mMonitor.Lock(); + MOZ_ASSERT(!mEOS); + mEOS = true; + MOZ_ASSERT(!mDrainComplete); + mDrainComplete = false; + mMonitor.Unlock(); + mMediaDataDecoder->Drain(); + } else { +#ifdef LOG_SAMPLE_DECODE + LOG("PopSample %s time=%lld dur=%lld", TrackTypeToStr(aTrack), + compressed->mTime, compressed->mDuration); +#endif + mMonitor.Lock(); + mDrainComplete = false; + mInputExhausted = false; + mNumSamplesInput++; + mMonitor.Unlock(); + if (NS_FAILED(mMediaDataDecoder->Input(compressed))) { + return false; + } + } + mMonitor.Lock(); + } + mMonitor.AssertCurrentThreadOwns(); + while (!mError && + prevNumFramesOutput == mNumSamplesOutput && + (!mInputExhausted || mEOS) && + !mDrainComplete) { + mMonitor.Wait(); + } + if (mError || + (mEOS && mDrainComplete)) { + break; + } + + } + mMonitor.AssertCurrentThreadOwns(); + bool rv = !(mEOS || mError); + mMonitor.Unlock(); + return rv; +} + +bool +IntelWebMVideoDecoder::SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint32_t& aParsed) +{ + MOZ_ASSERT(mReader->GetDecoder()); + + Flush(); + + // Loop until we reach the next keyframe after the threshold. + while (true) { + nsRefPtr compressed(PopSample()); + if (!compressed) { + // EOS, or error. Let the state machine know. + return false; + } + aParsed++; + if (!compressed->mKeyframe || + compressed->mTime < aTimeThreshold) { + continue; + } + mQueuedVideoSample = compressed; + break; + } + + return true; +} + +bool +IntelWebMVideoDecoder::DecodeVideoFrame(bool& aKeyframeSkip, + int64_t aTimeThreshold) +{ + AbstractMediaDecoder::AutoNotifyDecoded a(mReader->GetDecoder()); + + MOZ_ASSERT(mPlatform && mReader->GetDecoder()); + + if (aKeyframeSkip) { + bool ok = SkipVideoDemuxToNextKeyFrame(aTimeThreshold, a.mDropped); + if (!ok) { + NS_WARNING("Failed to skip demux up to next keyframe"); + return false; + } + a.mParsed = a.mDropped; + aKeyframeSkip = false; + nsresult rv = mMediaDataDecoder->Flush(); + NS_ENSURE_SUCCESS(rv, false); + } + + MOZ_ASSERT(mReader->OnTaskQueue()); + bool rv = Decode(); + { + // Report the number of "decoded" frames as the difference in the + // mNumSamplesOutput field since the last time we were called. + MonitorAutoLock mon(mMonitor); + uint64_t delta = mNumSamplesOutput - mLastReportedNumDecodedFrames; + a.mDecoded = static_cast(delta); + mLastReportedNumDecodedFrames = mNumSamplesOutput; + } + return rv; +} + +already_AddRefed +IntelWebMVideoDecoder::PopSample() +{ + if (mQueuedVideoSample) { + return mQueuedVideoSample.forget(); + } + nsRefPtr sample; + while (mSampleQueue.empty()) { + bool eos = false; + bool ok = Demux(sample, &eos); + if (!ok || eos) { + MOZ_ASSERT(!sample); + return nullptr; + } + MOZ_ASSERT(sample); + mSampleQueue.push_back(sample.forget()); + } + + MOZ_ASSERT(!mSampleQueue.empty()); + sample = mSampleQueue.front().forget(); + mSampleQueue.pop_front(); + return sample.forget(); +} + +void +IntelWebMVideoDecoder::Output(MediaData* aSample) +{ +#ifdef LOG_SAMPLE_DECODE + LOG("Decoded video sample time=%lld dur=%lld", + aSample->mTime, aSample->mDuration); +#endif + + // Don't accept output while we're flushing. + MonitorAutoLock mon(mMonitor); + if (mIsFlushing) { + mon.NotifyAll(); + return; + } + + MOZ_ASSERT(aSample->mType == MediaData::VIDEO_DATA); + mReader->VideoQueue().Push(static_cast(aSample)); + + mNumSamplesOutput++; + mon.NotifyAll(); +} + +void +IntelWebMVideoDecoder::DrainComplete() +{ + MonitorAutoLock mon(mMonitor); + mDrainComplete = true; + mon.NotifyAll(); +} + +void +IntelWebMVideoDecoder::InputExhausted() +{ + MonitorAutoLock mon(mMonitor); + mInputExhausted = true; + mon.NotifyAll(); +} + +void +IntelWebMVideoDecoder::Error() +{ + MonitorAutoLock mon(mMonitor); + mError = true; + mon.NotifyAll(); +} + +nsresult +IntelWebMVideoDecoder::Flush() +{ + if (!mReader->GetDecoder()) { + return NS_ERROR_FAILURE; + } + // Purge the current decoder's state. + // Set a flag so that we ignore all output while we call + // MediaDataDecoder::Flush(). + { + MonitorAutoLock mon(mMonitor); + mIsFlushing = true; + mDrainComplete = false; + mEOS = false; + } + mMediaDataDecoder->Flush(); + { + MonitorAutoLock mon(mMonitor); + mIsFlushing = false; + } + return NS_OK; +} + +} // namespace mozilla diff --git a/dom/media/webm/IntelWebMVideoDecoder.h b/dom/media/webm/IntelWebMVideoDecoder.h new file mode 100644 index 000000000000..4d8343c10dcf --- /dev/null +++ b/dom/media/webm/IntelWebMVideoDecoder.h @@ -0,0 +1,97 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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/. */ +#if !defined(IntelWebMVideoDecoder_h_) +#define IntelWebMVideoDecoder_h_ + +#include + +#include "WebMReader.h" +#include "nsAutoPtr.h" +#include "PlatformDecoderModule.h" +#include "mozilla/Monitor.h" + +#include "MediaInfo.h" +#include "MediaData.h" + +class TaskQueue; + +namespace mozilla { + +class VP8Sample; + +typedef std::deque> VP8SampleQueue; + +class IntelWebMVideoDecoder : public WebMVideoDecoder, public MediaDataDecoderCallback +{ +public: + static WebMVideoDecoder* Create(WebMReader* aReader); + virtual nsRefPtr Init(unsigned int aWidth = 0, + unsigned int aHeight = 0) override; + virtual nsresult Flush() override; + virtual void Shutdown() override; + + virtual bool DecodeVideoFrame(bool &aKeyframeSkip, + int64_t aTimeThreshold) override; + + virtual void Output(MediaData* aSample) override; + + virtual void DrainComplete() override; + + virtual void InputExhausted() override; + virtual void Error() override; + + virtual bool OnReaderTaskQueue() override + { + return mReader->OnTaskQueue(); + } + + IntelWebMVideoDecoder(WebMReader* aReader); + ~IntelWebMVideoDecoder(); + +private: + void InitLayersBackendType(); + + bool Decode(); + + bool Demux(nsRefPtr& aSample, bool* aEOS); + + bool SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint32_t& parsed); + + bool IsSupportedVideoMimeType(const nsACString& aMimeType); + + already_AddRefed PopSample(); + + nsRefPtr mReader; + nsRefPtr mPlatform; + nsRefPtr mMediaDataDecoder; + + // TaskQueue on which decoder can choose to decode. + // Only non-null up until the decoder is created. + nsRefPtr mTaskQueue; + + // Monitor that protects all non-threadsafe state; the primitives + // that follow. + Monitor mMonitor; + nsAutoPtr mDecoderConfig; + + VP8SampleQueue mSampleQueue; + nsRefPtr mQueuedVideoSample; + uint64_t mNumSamplesInput; + uint64_t mNumSamplesOutput; + uint64_t mLastReportedNumDecodedFrames; + uint32_t mDecodeAhead; + + // Whether this stream exists in the media. + bool mInputExhausted; + bool mDrainComplete; + bool mError; + bool mEOS; + bool mIsFlushing; +}; + +} // namespace mozilla + +#endif diff --git a/dom/media/webm/SoftwareWebMVideoDecoder.cpp b/dom/media/webm/SoftwareWebMVideoDecoder.cpp index f7f6453b5b52..3e46e4ec6cc4 100644 --- a/dom/media/webm/SoftwareWebMVideoDecoder.cpp +++ b/dom/media/webm/SoftwareWebMVideoDecoder.cpp @@ -53,10 +53,16 @@ SoftwareWebMVideoDecoder::Create(WebMReader* aReader) return new SoftwareWebMVideoDecoder(aReader); } -nsresult +nsRefPtr SoftwareWebMVideoDecoder::Init(unsigned int aWidth, unsigned int aHeight) { - return InitDecoder(aWidth, aHeight); + nsresult rv = InitDecoder(aWidth, aHeight); + + if (NS_SUCCEEDED(rv)) { + return InitPromise::CreateAndResolve(TrackType::kVideoTrack, __func__); + } + + return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__); } nsresult diff --git a/dom/media/webm/SoftwareWebMVideoDecoder.h b/dom/media/webm/SoftwareWebMVideoDecoder.h index 2d3950691ab4..defa631638c0 100644 --- a/dom/media/webm/SoftwareWebMVideoDecoder.h +++ b/dom/media/webm/SoftwareWebMVideoDecoder.h @@ -17,8 +17,8 @@ class SoftwareWebMVideoDecoder : public WebMVideoDecoder public: static WebMVideoDecoder* Create(WebMReader* aReader); - virtual nsresult Init(unsigned int aWidth = 0, - unsigned int aHeight = 0) override; + virtual nsRefPtr Init(unsigned int aWidth = 0, + unsigned int aHeight = 0) override; virtual bool DecodeVideoFrame(bool &aKeyframeSkip, int64_t aTimeThreshold) override; diff --git a/dom/media/webm/WebMReader.cpp b/dom/media/webm/WebMReader.cpp index a0e42b85d937..9fe76f1ee58a 100644 --- a/dom/media/webm/WebMReader.cpp +++ b/dom/media/webm/WebMReader.cpp @@ -20,6 +20,11 @@ #include "vpx/vp8dx.h" #include "vpx/vpx_decoder.h" +// IntelWebMVideoDecoder uses the WMF backend, which is Windows Vista+ only. +#if defined(MOZ_PDM_VPX) +#include "IntelWebMVideoDecoder.h" +#endif + // Un-comment to enable logging of seek bisections. //#define SEEK_LOGGING @@ -120,6 +125,10 @@ static void webm_log(nestegg * context, va_end(args); } +#if defined(MOZ_PDM_VPX) +static bool sIsIntelDecoderEnabled = false; +#endif + WebMReader::WebMReader(AbstractMediaDecoder* aDecoder, TaskQueue* aBorrowedTaskQueue) : MediaDecoderReader(aDecoder, aBorrowedTaskQueue) , mContext(nullptr) @@ -140,6 +149,10 @@ WebMReader::WebMReader(AbstractMediaDecoder* aDecoder, TaskQueue* aBorrowedTaskQ if (!gNesteggLog) { gNesteggLog = PR_NewLogModule("Nestegg"); } + +#if defined(MOZ_PDM_VPX) + sIsIntelDecoderEnabled = Preferences::GetBool("media.webm.intel_decoder.enabled", false); +#endif } WebMReader::~WebMReader() @@ -155,6 +168,12 @@ WebMReader::~WebMReader() nsRefPtr WebMReader::Shutdown() { +#if defined(MOZ_PDM_VPX) + if (mVideoTaskQueue) { + mVideoTaskQueue->BeginShutdown(); + mVideoTaskQueue->AwaitShutdownAndIdle(); + } +#endif if (mAudioDecoder) { mAudioDecoder->Shutdown(); mAudioDecoder = nullptr; @@ -170,6 +189,18 @@ WebMReader::Shutdown() nsresult WebMReader::Init(MediaDecoderReader* aCloneDonor) { +#if defined(MOZ_PDM_VPX) + if (sIsIntelDecoderEnabled) { + PlatformDecoderModule::Init(); + + InitLayersBackendType(); + + mVideoTaskQueue = new FlushableTaskQueue( + SharedThreadPool::Get(NS_LITERAL_CSTRING("IntelVP8 Video Decode"))); + NS_ENSURE_TRUE(mVideoTaskQueue, NS_ERROR_FAILURE); + } +#endif + if (aCloneDonor) { mBufferedState = static_cast(aCloneDonor)->mBufferedState; } else { @@ -296,13 +327,23 @@ WebMReader::RetrieveWebMMetadata(MediaInfo* aInfo) mVideoCodec = nestegg_track_codec_id(mContext, track); +#if defined(MOZ_PDM_VPX) + if (sIsIntelDecoderEnabled) { + mVideoDecoder = IntelWebMVideoDecoder::Create(this); + } +#endif + + // If there's no decoder yet (e.g. HW decoder not available), use the software decoder. if (!mVideoDecoder) { mVideoDecoder = SoftwareWebMVideoDecoder::Create(this); } - if (!mVideoDecoder || - NS_FAILED(mVideoDecoder->Init(params.display_width, - params.display_height))) { + if (mVideoDecoder) { + mInitPromises.AppendElement(mVideoDecoder->Init(params.display_width, + params.display_height)); + } + + if (!mVideoDecoder) { Cleanup(); return NS_ERROR_FAILURE; } @@ -383,7 +424,9 @@ WebMReader::RetrieveWebMMetadata(MediaInfo* aInfo) return NS_ERROR_FAILURE; } - if (!mAudioDecoder || NS_FAILED(mAudioDecoder->Init())) { + if (mAudioDecoder) { + mInitPromises.AppendElement(mAudioDecoder->Init()); + } else { Cleanup(); return NS_ERROR_FAILURE; } diff --git a/dom/media/webm/WebMReader.h b/dom/media/webm/WebMReader.h index 8060654aaca2..6df8b4d67efb 100644 --- a/dom/media/webm/WebMReader.h +++ b/dom/media/webm/WebMReader.h @@ -11,6 +11,7 @@ #include "FlushableTaskQueue.h" #include "MediaDecoderReader.h" #include "MediaResource.h" +#include "PlatformDecoderModule.h" #include "nsAutoRef.h" #include "nestegg/nestegg.h" @@ -25,7 +26,9 @@ namespace mozilla { static const unsigned NS_PER_USEC = 1000; static const double NS_PER_S = 1e9; +typedef MediaDataDecoder::InitPromise InitPromise; typedef TrackInfo::TrackType TrackType; +typedef MediaDataDecoder::DecoderFailureReason DecoderFailureReason; class WebMBufferedState; class WebMPacketQueue; @@ -36,7 +39,7 @@ class WebMReader; class WebMVideoDecoder { public: - virtual nsresult Init(unsigned int aWidth = 0, unsigned int aHeight = 0) = 0; + virtual nsRefPtr Init(unsigned int aWidth = 0, unsigned int aHeight = 0) = 0; virtual nsresult Flush() { return NS_OK; } virtual void Shutdown() = 0; virtual bool DecodeVideoFrame(bool &aKeyframeSkip, @@ -49,7 +52,7 @@ public: class WebMAudioDecoder { public: - virtual nsresult Init() = 0; + virtual nsRefPtr Init() = 0; virtual void Shutdown() = 0; virtual nsresult ResetDecode() = 0; virtual nsresult DecodeHeader(const unsigned char* aData, size_t aLength) = 0; @@ -119,6 +122,7 @@ public: int64_t GetLastVideoFrameTime(); void SetLastVideoFrameTime(int64_t aFrameTime); layers::LayersBackend GetLayersBackendType() { return mLayersBackendType; } + FlushableTaskQueue* GetVideoTaskQueue() { return mVideoTaskQueue; } uint64_t GetCodecDelay() { return mCodecDelay; } protected: @@ -163,6 +167,8 @@ private: nsAutoPtr mAudioDecoder; nsAutoPtr mVideoDecoder; + nsTArray> mInitPromises; + // Queue of video and audio packets that have been read but not decoded. These // must only be accessed from the decode thread. WebMPacketQueue mVideoPackets; @@ -206,6 +212,9 @@ private: layers::LayersBackend mLayersBackendType; + // For hardware video decoding. + nsRefPtr mVideoTaskQueue; + // Booleans to indicate if we have audio and/or video data bool mHasVideo; bool mHasAudio; diff --git a/dom/media/webm/moz.build b/dom/media/webm/moz.build index 8dd3e99bf24d..cab25d63ee3a 100644 --- a/dom/media/webm/moz.build +++ b/dom/media/webm/moz.build @@ -5,6 +5,7 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. EXPORTS += [ + 'IntelWebMVideoDecoder.h', 'NesteggPacketHolder.h', 'SoftwareWebMVideoDecoder.h', 'WebMBufferedParser.h', @@ -22,6 +23,10 @@ UNIFIED_SOURCES += [ 'WebMReader.cpp', ] +if CONFIG['MOZ_FMP4'] and CONFIG['MOZ_WMF']: + DEFINES['MOZ_PDM_VPX'] = True + UNIFIED_SOURCES += ['IntelWebMVideoDecoder.cpp'] + if CONFIG['MOZ_WEBM_ENCODER']: EXPORTS += ['WebMWriter.h'] UNIFIED_SOURCES += ['EbmlComposer.cpp', From e7aabfcb3a1be0e19ba519369575f26b5ce82d80 Mon Sep 17 00:00:00 2001 From: JW Wang Date: Wed, 7 Oct 2015 12:09:34 +0800 Subject: [PATCH 170/228] Bug 1211787 - Improve the accuracy of MediaDecoderStateMachine::GetDecodedAudioDuration(). r=roc. --- dom/media/MediaDecoderStateMachine.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp index b9b354734650..fb82ef418a81 100644 --- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -400,14 +400,17 @@ bool MediaDecoderStateMachine::HaveNextFrameData() (!HasVideo() || VideoQueue().GetSize() > 1); } -int64_t MediaDecoderStateMachine::GetDecodedAudioDuration() +int64_t +MediaDecoderStateMachine::GetDecodedAudioDuration() { MOZ_ASSERT(OnTaskQueue()); - int64_t audioDecoded = AudioQueue().Duration(); if (mMediaSink->IsStarted()) { - audioDecoded += AudioEndTime() - GetMediaTime(); + // |mDecodedAudioEndTime == -1| means no decoded audio at all so the + // returned duration is 0. + return mDecodedAudioEndTime != -1 ? mDecodedAudioEndTime - GetClock() : 0; } - return audioDecoded; + // MediaSink not started. All audio samples are in the queue. + return AudioQueue().Duration(); } void MediaDecoderStateMachine::DiscardStreamData() From c1ecd2ffc8aa02804d35b706f6e77c2a59a0188a Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Wed, 7 Oct 2015 11:55:09 +0200 Subject: [PATCH 171/228] Bug 1211962 - addNativeToBytecodeEntry: Check that the masm.currentOffset() returns a valid result. r=djvj --- js/src/jit-test/tests/profiler/bug1211962.js | 11 +++++++++++ js/src/jit/shared/CodeGenerator-shared.cpp | 5 +++++ 2 files changed, 16 insertions(+) create mode 100644 js/src/jit-test/tests/profiler/bug1211962.js diff --git a/js/src/jit-test/tests/profiler/bug1211962.js b/js/src/jit-test/tests/profiler/bug1211962.js new file mode 100644 index 000000000000..532fa93fc605 --- /dev/null +++ b/js/src/jit-test/tests/profiler/bug1211962.js @@ -0,0 +1,11 @@ +// |jit-test| slow; +load(libdir + "oomTest.js"); + +enableSPSProfiling(); +var lfGlobal = newGlobal(); +for (lfLocal in this) { + lfGlobal[lfLocal] = this[lfLocal]; +} +const script = 'oomTest(() => getBacktrace({args: true, locals: "123795", thisprops: true}));'; +lfGlobal.offThreadCompileScript(script); +lfGlobal.runOffThreadScript(); diff --git a/js/src/jit/shared/CodeGenerator-shared.cpp b/js/src/jit/shared/CodeGenerator-shared.cpp index 73e61e0d93e7..ad23f6002089 100644 --- a/js/src/jit/shared/CodeGenerator-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-shared.cpp @@ -208,6 +208,11 @@ CodeGeneratorShared::addNativeToBytecodeEntry(const BytecodeSite* site) if (!isProfilerInstrumentationEnabled()) return true; + // Fails early if the last added instruction caused the macro assembler to + // run out of memory as continuity assumption below do not hold. + if (masm.oom()) + return false; + MOZ_ASSERT(site); MOZ_ASSERT(site->tree()); MOZ_ASSERT(site->pc()); From 68837e75384398feda378881e1c20444299d4cd8 Mon Sep 17 00:00:00 2001 From: JW Wang Date: Wed, 7 Oct 2015 14:27:26 +0800 Subject: [PATCH 172/228] Bug 1211793 - Remove unnecessary creation of "MediaDecoder" log module. r=gerald. --- dom/media/omx/MediaOmxCommonDecoder.cpp | 3 --- dom/media/omx/MediaOmxCommonReader.cpp | 4 ---- dom/media/omx/MediaOmxReader.cpp | 4 ---- dom/media/webaudio/BufferDecoder.cpp | 5 ----- 4 files changed, 16 deletions(-) diff --git a/dom/media/omx/MediaOmxCommonDecoder.cpp b/dom/media/omx/MediaOmxCommonDecoder.cpp index 4f32ab7ce824..7abca33208aa 100644 --- a/dom/media/omx/MediaOmxCommonDecoder.cpp +++ b/dom/media/omx/MediaOmxCommonDecoder.cpp @@ -31,9 +31,6 @@ MediaOmxCommonDecoder::MediaOmxCommonDecoder() , mIsCaptured(false) { mDormantSupported = true; - if (!gMediaDecoderLog) { - gMediaDecoderLog = PR_NewLogModule("MediaDecoder"); - } } MediaOmxCommonDecoder::~MediaOmxCommonDecoder() {} diff --git a/dom/media/omx/MediaOmxCommonReader.cpp b/dom/media/omx/MediaOmxCommonReader.cpp index d8c5d2080536..280bc26f35b2 100644 --- a/dom/media/omx/MediaOmxCommonReader.cpp +++ b/dom/media/omx/MediaOmxCommonReader.cpp @@ -30,10 +30,6 @@ MediaOmxCommonReader::MediaOmxCommonReader(AbstractMediaDecoder *aDecoder) : MediaDecoderReader(aDecoder) , mStreamSource(nullptr) { - if (!gMediaDecoderLog) { - gMediaDecoderLog = PR_NewLogModule("MediaDecoder"); - } - mAudioChannel = dom::AudioChannelService::GetDefaultAudioChannel(); } diff --git a/dom/media/omx/MediaOmxReader.cpp b/dom/media/omx/MediaOmxReader.cpp index bc3f54caaa98..dcb586206a42 100644 --- a/dom/media/omx/MediaOmxReader.cpp +++ b/dom/media/omx/MediaOmxReader.cpp @@ -128,10 +128,6 @@ MediaOmxReader::MediaOmxReader(AbstractMediaDecoder *aDecoder) , mIsShutdown(false) , mMP3FrameParser(-1) { - if (!gMediaDecoderLog) { - gMediaDecoderLog = PR_NewLogModule("MediaDecoder"); - } - mAudioChannel = dom::AudioChannelService::GetDefaultAudioChannel(); } diff --git a/dom/media/webaudio/BufferDecoder.cpp b/dom/media/webaudio/BufferDecoder.cpp index 8d3b5643dcf6..5b84157d7315 100644 --- a/dom/media/webaudio/BufferDecoder.cpp +++ b/dom/media/webaudio/BufferDecoder.cpp @@ -11,8 +11,6 @@ namespace mozilla { -extern PRLogModuleInfo* gMediaDecoderLog; - NS_IMPL_ISUPPORTS0(BufferDecoder) BufferDecoder::BufferDecoder(MediaResource* aResource) @@ -20,9 +18,6 @@ BufferDecoder::BufferDecoder(MediaResource* aResource) { MOZ_ASSERT(NS_IsMainThread()); MOZ_COUNT_CTOR(BufferDecoder); - if (!gMediaDecoderLog) { - gMediaDecoderLog = PR_NewLogModule("MediaDecoder"); - } } BufferDecoder::~BufferDecoder() From 7187bae5a8480e676b6581f4df995391bca90672 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Wed, 7 Oct 2015 11:04:37 +0100 Subject: [PATCH 173/228] Bug 1208665 r=Waldo a=abillings --- js/public/Utility.h | 49 +++++++++++++++++++++++++++++++------ js/src/ds/LifoAlloc.h | 17 +++++++------ js/src/jit/FixedList.h | 10 +++++--- js/src/jit/JitAllocPolicy.h | 21 +++++++++------- js/src/jit/LIR.cpp | 3 +-- js/src/jit/MIRGenerator.h | 7 +++--- js/src/jit/MIRGraph.cpp | 2 +- js/src/jsalloc.h | 14 ++++++++--- js/src/vm/MallocProvider.h | 39 ++++++++++++----------------- js/src/vm/Runtime.h | 10 +++++--- 10 files changed, 106 insertions(+), 66 deletions(-) diff --git a/js/public/Utility.h b/js/public/Utility.h index 5b36e5eec0b0..2e32c1ae80e1 100644 --- a/js/public/Utility.h +++ b/js/public/Utility.h @@ -336,6 +336,36 @@ static inline char* js_strdup(const char* s) JS_DECLARE_NEW_METHODS(js_new, js_malloc, static MOZ_ALWAYS_INLINE) +namespace js { + +/* + * Calculate the number of bytes needed to allocate |numElems| contiguous + * instances of type |T|. Return false if the calculation overflowed. + */ +template +MOZ_WARN_UNUSED_RESULT inline bool +CalculateAllocSize(size_t numElems, size_t* bytesOut) +{ + *bytesOut = numElems * sizeof(T); + return (numElems & mozilla::tl::MulOverflowMask::value) == 0; +} + +/* + * Calculate the number of bytes needed to allocate a single instance of type + * |T| followed by |numExtra| contiguous instances of type |Extra|. Return + * false if the calculation overflowed. + */ +template +MOZ_WARN_UNUSED_RESULT inline bool +CalculateAllocSizeWithExtra(size_t numExtra, size_t* bytesOut) +{ + *bytesOut = sizeof(T) + numExtra * sizeof(Extra); + return (numExtra & mozilla::tl::MulOverflowMask::value) == 0 && + *bytesOut >= sizeof(T); +} + +} /* namespace js */ + template static MOZ_ALWAYS_INLINE void js_delete(const T* p) @@ -361,32 +391,34 @@ template static MOZ_ALWAYS_INLINE T* js_pod_malloc() { - return (T*)js_malloc(sizeof(T)); + return static_cast(js_malloc(sizeof(T))); } template static MOZ_ALWAYS_INLINE T* js_pod_calloc() { - return (T*)js_calloc(sizeof(T)); + return static_cast(js_calloc(sizeof(T))); } template static MOZ_ALWAYS_INLINE T* js_pod_malloc(size_t numElems) { - if (MOZ_UNLIKELY(numElems & mozilla::tl::MulOverflowMask::value)) + size_t bytes; + if (MOZ_UNLIKELY(!js::CalculateAllocSize(numElems, &bytes))) return nullptr; - return (T*)js_malloc(numElems * sizeof(T)); + return static_cast(js_malloc(bytes)); } template static MOZ_ALWAYS_INLINE T* js_pod_calloc(size_t numElems) { - if (MOZ_UNLIKELY(numElems & mozilla::tl::MulOverflowMask::value)) + size_t bytes; + if (MOZ_UNLIKELY(!js::CalculateAllocSize(numElems, &bytes))) return nullptr; - return (T*)js_calloc(numElems * sizeof(T)); + return static_cast(js_calloc(bytes)); } template @@ -394,9 +426,10 @@ static MOZ_ALWAYS_INLINE T* js_pod_realloc(T* prior, size_t oldSize, size_t newSize) { MOZ_ASSERT(!(oldSize & mozilla::tl::MulOverflowMask::value)); - if (MOZ_UNLIKELY(newSize & mozilla::tl::MulOverflowMask::value)) + size_t bytes; + if (MOZ_UNLIKELY(!js::CalculateAllocSize(newSize, &bytes))) return nullptr; - return (T*)js_realloc(prior, newSize * sizeof(T)); + return static_cast(js_realloc(prior, bytes)); } namespace js { diff --git a/js/src/ds/LifoAlloc.h b/js/src/ds/LifoAlloc.h index 227a3ed777f7..689c933ea677 100644 --- a/js/src/ds/LifoAlloc.h +++ b/js/src/ds/LifoAlloc.h @@ -315,9 +315,10 @@ class LifoAlloc // The caller is responsible for initialization. template T* newArrayUninitialized(size_t count) { - if (MOZ_UNLIKELY(count & mozilla::tl::MulOverflowMask::value)) + size_t bytes; + if (MOZ_UNLIKELY(!CalculateAllocSize(count, &bytes))) return nullptr; - return static_cast(alloc(sizeof(T) * count)); + return static_cast(alloc(bytes)); } class Mark { @@ -532,24 +533,24 @@ class LifoAllocPolicy {} template T* maybe_pod_malloc(size_t numElems) { - if (MOZ_UNLIKELY(numElems & mozilla::tl::MulOverflowMask::value)) + size_t bytes; + if (MOZ_UNLIKELY(!CalculateAllocSize(numElems, &bytes))) return nullptr; - size_t bytes = numElems * sizeof(T); void* p = fb == Fallible ? alloc_.alloc(bytes) : alloc_.allocInfallible(bytes); return static_cast(p); } template T* maybe_pod_calloc(size_t numElems) { - T* p = pod_malloc(numElems); - if (fb == Fallible && !p) + T* p = maybe_pod_malloc(numElems); + if (MOZ_UNLIKELY(!p)) return nullptr; memset(p, 0, numElems * sizeof(T)); return p; } template T* maybe_pod_realloc(T* p, size_t oldSize, size_t newSize) { - T* n = pod_malloc(newSize); - if (fb == Fallible && !n) + T* n = maybe_pod_malloc(newSize); + if (MOZ_UNLIKELY(!n)) return nullptr; MOZ_ASSERT(!(oldSize & mozilla::tl::MulOverflowMask::value)); memcpy(n, p, Min(oldSize * sizeof(T), newSize * sizeof(T))); diff --git a/js/src/jit/FixedList.h b/js/src/jit/FixedList.h index 9cea3a807557..b6b37bbebe68 100644 --- a/js/src/jit/FixedList.h +++ b/js/src/jit/FixedList.h @@ -37,9 +37,10 @@ class FixedList if (length == 0) return true; - if (MOZ_UNLIKELY(length & mozilla::tl::MulOverflowMask::value)) + size_t bytes; + if (MOZ_UNLIKELY(!CalculateAllocSize(length, &bytes))) return false; - list_ = (T*)alloc.allocate(length * sizeof(T)); + list_ = (T*)alloc.allocate(bytes); return list_ != nullptr; } @@ -60,9 +61,10 @@ class FixedList size_t newlength = length_ + num; if (newlength < length_) return false; - if (MOZ_UNLIKELY(newlength & mozilla::tl::MulOverflowMask::value)) + size_t bytes; + if (MOZ_UNLIKELY(!CalculateAllocSize(newlength, &bytes))) return false; - T* list = (T*)alloc.allocate((length_ + num) * sizeof(T)); + T* list = (T*)alloc.allocate(bytes); if (MOZ_UNLIKELY(!list)) return false; diff --git a/js/src/jit/JitAllocPolicy.h b/js/src/jit/JitAllocPolicy.h index 91827de8ffe8..9544e1a13cb3 100644 --- a/js/src/jit/JitAllocPolicy.h +++ b/js/src/jit/JitAllocPolicy.h @@ -48,12 +48,13 @@ class TempAllocator return p; } - template - void* allocateArray(size_t n) + template + T* allocateArray(size_t n) { - if (MOZ_UNLIKELY(n & mozilla::tl::MulOverflowMask::value)) + size_t bytes; + if (MOZ_UNLIKELY(!CalculateAllocSize(n, &bytes))) return nullptr; - void* p = lifoScope_.alloc().alloc(n * ElemSize); + T* p = static_cast(lifoScope_.alloc().alloc(bytes)); if (MOZ_UNLIKELY(!ensureBallast())) return nullptr; return p; @@ -79,13 +80,14 @@ class JitAllocPolicy {} template T* maybe_pod_malloc(size_t numElems) { - if (MOZ_UNLIKELY(numElems & mozilla::tl::MulOverflowMask::value)) + size_t bytes; + if (MOZ_UNLIKELY(!CalculateAllocSize(numElems, &bytes))) return nullptr; - return static_cast(alloc_.allocate(numElems * sizeof(T))); + return static_cast(alloc_.allocate(bytes)); } template T* maybe_pod_calloc(size_t numElems) { - T* p = pod_malloc(numElems); + T* p = maybe_pod_malloc(numElems); if (MOZ_LIKELY(p)) memset(p, 0, numElems * sizeof(T)); return p; @@ -127,9 +129,10 @@ class OldJitAllocPolicy {} template T* maybe_pod_malloc(size_t numElems) { - if (MOZ_UNLIKELY(numElems & mozilla::tl::MulOverflowMask::value)) + size_t bytes; + if (MOZ_UNLIKELY(!CalculateAllocSize(numElems, &bytes))) return nullptr; - return static_cast(GetJitContext()->temp->allocate(numElems * sizeof(T))); + return static_cast(GetJitContext()->temp->allocate(bytes)); } template T* pod_malloc(size_t numElems) { diff --git a/js/src/jit/LIR.cpp b/js/src/jit/LIR.cpp index 5ba641ca2c7c..298a1a7e4da2 100644 --- a/js/src/jit/LIR.cpp +++ b/js/src/jit/LIR.cpp @@ -107,8 +107,7 @@ LBlock::init(TempAllocator& alloc) int numPhis = (phi->type() == MIRType_Value) ? BOX_PIECES : 1; for (int i = 0; i < numPhis; i++) { - void* array = alloc.allocateArray(numPreds); - LAllocation* inputs = static_cast(array); + LAllocation* inputs = alloc.allocateArray(numPreds); if (!inputs) return false; diff --git a/js/src/jit/MIRGenerator.h b/js/src/jit/MIRGenerator.h index 7053e5e4a722..24aaf107f87d 100644 --- a/js/src/jit/MIRGenerator.h +++ b/js/src/jit/MIRGenerator.h @@ -62,10 +62,11 @@ class MIRGenerator } template - T * allocate(size_t count = 1) { - if (count & mozilla::tl::MulOverflowMask::value) + T* allocate(size_t count = 1) { + size_t bytes; + if (MOZ_UNLIKELY(!CalculateAllocSize(count, &bytes))) return nullptr; - return reinterpret_cast(alloc().allocate(sizeof(T) * count)); + return static_cast(alloc().allocate(bytes)); } // Set an error state and prints a message. Returns false so errors can be diff --git a/js/src/jit/MIRGraph.cpp b/js/src/jit/MIRGraph.cpp index 4fb4b80826a3..ffc973f2bfe0 100644 --- a/js/src/jit/MIRGraph.cpp +++ b/js/src/jit/MIRGraph.cpp @@ -346,7 +346,7 @@ MBasicBlock::NewAsmJS(MIRGraph& graph, CompileInfo& info, MBasicBlock* pred, Kin size_t nphis = block->stackPosition_; TempAllocator& alloc = graph.alloc(); - MPhi* phis = (MPhi*)alloc.allocateArray(nphis); + MPhi* phis = alloc.allocateArray(nphis); if (!phis) return nullptr; diff --git a/js/src/jsalloc.h b/js/src/jsalloc.h index 5c5e1ee46c99..b9ae51901c20 100644 --- a/js/src/jsalloc.h +++ b/js/src/jsalloc.h @@ -71,6 +71,14 @@ class TempAllocPolicy JS_FRIEND_API(void*) onOutOfMemory(AllocFunction allocFunc, size_t nbytes, void* reallocPtr = nullptr); + template + T* onOutOfMemoryTyped(AllocFunction allocFunc, size_t numElems, void* reallocPtr = nullptr) { + size_t bytes; + if (MOZ_UNLIKELY(!CalculateAllocSize(numElems, &bytes))) + return nullptr; + return static_cast(onOutOfMemory(allocFunc, bytes, reallocPtr)); + } + public: MOZ_IMPLICIT TempAllocPolicy(JSContext* cx) : cx_((ContextFriendFields*) cx) {} // :( MOZ_IMPLICIT TempAllocPolicy(ContextFriendFields* cx) : cx_(cx) {} @@ -94,7 +102,7 @@ class TempAllocPolicy T* pod_malloc(size_t numElems) { T* p = maybe_pod_malloc(numElems); if (MOZ_UNLIKELY(!p)) - p = static_cast(onOutOfMemory(AllocFunction::Malloc, numElems * sizeof(T))); + p = onOutOfMemoryTyped(AllocFunction::Malloc, numElems); return p; } @@ -102,7 +110,7 @@ class TempAllocPolicy T* pod_calloc(size_t numElems) { T* p = maybe_pod_calloc(numElems); if (MOZ_UNLIKELY(!p)) - p = static_cast(onOutOfMemory(AllocFunction::Calloc, numElems * sizeof(T))); + p = onOutOfMemoryTyped(AllocFunction::Calloc, numElems); return p; } @@ -110,7 +118,7 @@ class TempAllocPolicy T* pod_realloc(T* prior, size_t oldSize, size_t newSize) { T* p2 = maybe_pod_realloc(prior, oldSize, newSize); if (MOZ_UNLIKELY(!p2)) - p2 = static_cast(onOutOfMemory(AllocFunction::Realloc, newSize * sizeof(T), prior)); + p2 = onOutOfMemoryTyped(AllocFunction::Realloc, newSize, prior); return p2; } diff --git a/js/src/vm/MallocProvider.h b/js/src/vm/MallocProvider.h index 168b2e50fa76..6d6eb1c886a7 100644 --- a/js/src/vm/MallocProvider.h +++ b/js/src/vm/MallocProvider.h @@ -52,19 +52,17 @@ struct MallocProvider { template T* maybe_pod_malloc(size_t numElems) { - size_t bytes = numElems * sizeof(T); T* p = js_pod_malloc(numElems); if (MOZ_LIKELY(p)) - client()->updateMallocCounter(bytes); + client()->updateMallocCounter(numElems * sizeof(T)); return p; } template T* maybe_pod_calloc(size_t numElems) { - size_t bytes = numElems * sizeof(T); T* p = js_pod_calloc(numElems); if (MOZ_LIKELY(p)) - client()->updateMallocCounter(bytes); + client()->updateMallocCounter(numElems * sizeof(T)); return p; } @@ -90,11 +88,11 @@ struct MallocProvider T* p = maybe_pod_malloc(numElems); if (MOZ_LIKELY(p)) return p; - if (numElems & mozilla::tl::MulOverflowMask::value) { + size_t bytes; + if (MOZ_UNLIKELY(!CalculateAllocSize(numElems, &bytes))) { client()->reportAllocationOverflow(); return nullptr; } - size_t bytes = numElems * sizeof(T); p = (T*)client()->onOutOfMemory(AllocFunction::Malloc, bytes); if (p) client()->updateMallocCounter(bytes); @@ -103,16 +101,12 @@ struct MallocProvider template T* pod_malloc_with_extra(size_t numExtra) { - if (MOZ_UNLIKELY(numExtra & mozilla::tl::MulOverflowMask::value)) { + size_t bytes; + if (MOZ_UNLIKELY((!CalculateAllocSizeWithExtra(numExtra, &bytes)))) { client()->reportAllocationOverflow(); return nullptr; } - size_t bytes = sizeof(T) + numExtra * sizeof(U); - if (MOZ_UNLIKELY(bytes < sizeof(T))) { - client()->reportAllocationOverflow(); - return nullptr; - } - T* p = reinterpret_cast(js_pod_malloc(bytes)); + T* p = static_cast(js_malloc(bytes)); if (MOZ_LIKELY(p)) { client()->updateMallocCounter(bytes); return p; @@ -139,11 +133,11 @@ struct MallocProvider T* p = maybe_pod_calloc(numElems); if (MOZ_LIKELY(p)) return p; - if (numElems & mozilla::tl::MulOverflowMask::value) { + size_t bytes; + if (MOZ_UNLIKELY(!CalculateAllocSize(numElems, &bytes))) { client()->reportAllocationOverflow(); return nullptr; } - size_t bytes = numElems * sizeof(T); p = (T*)client()->onOutOfMemory(AllocFunction::Calloc, bytes); if (p) client()->updateMallocCounter(bytes); @@ -152,16 +146,12 @@ struct MallocProvider template T* pod_calloc_with_extra(size_t numExtra) { - if (MOZ_UNLIKELY(numExtra & mozilla::tl::MulOverflowMask::value)) { + size_t bytes; + if (MOZ_UNLIKELY((!CalculateAllocSizeWithExtra(numExtra, &bytes)))) { client()->reportAllocationOverflow(); return nullptr; } - size_t bytes = sizeof(T) + numExtra * sizeof(U); - if (MOZ_UNLIKELY(bytes < sizeof(T))) { - client()->reportAllocationOverflow(); - return nullptr; - } - T* p = reinterpret_cast(js_pod_calloc(bytes)); + T* p = static_cast(js_calloc(bytes)); if (p) { client()->updateMallocCounter(bytes); return p; @@ -184,11 +174,12 @@ struct MallocProvider T* p = maybe_pod_realloc(prior, oldSize, newSize); if (MOZ_LIKELY(p)) return p; - if (newSize & mozilla::tl::MulOverflowMask::value) { + size_t bytes; + if (MOZ_UNLIKELY(!CalculateAllocSize(newSize, &bytes))) { client()->reportAllocationOverflow(); return nullptr; } - p = (T*)client()->onOutOfMemory(AllocFunction::Realloc, newSize * sizeof(T), prior); + p = (T*)client()->onOutOfMemory(AllocFunction::Realloc, bytes, prior); if (p && newSize > oldSize) client()->updateMallocCounter((newSize - oldSize) * sizeof(T)); return p; diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 93cb0c0c4aa5..1a953cd1e13e 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -1460,11 +1460,12 @@ struct JSRuntime : public JS::shadow::Runtime, T* p = pod_calloc(numElems); if (MOZ_LIKELY(!!p)) return p; - if (numElems & mozilla::tl::MulOverflowMask::value) { + size_t bytes; + if (MOZ_UNLIKELY(!js::CalculateAllocSize(numElems, &bytes))) { reportAllocationOverflow(); return nullptr; } - return (T*)onOutOfMemoryCanGC(js::AllocFunction::Calloc, numElems * sizeof(T)); + return static_cast(onOutOfMemoryCanGC(js::AllocFunction::Calloc, bytes)); } template @@ -1472,11 +1473,12 @@ struct JSRuntime : public JS::shadow::Runtime, T* p2 = pod_realloc(p, oldSize, newSize); if (MOZ_LIKELY(!!p2)) return p2; - if (newSize & mozilla::tl::MulOverflowMask::value) { + size_t bytes; + if (MOZ_UNLIKELY(!js::CalculateAllocSize(newSize, &bytes))) { reportAllocationOverflow(); return nullptr; } - return (T*)onOutOfMemoryCanGC(js::AllocFunction::Realloc, newSize * sizeof(T), p); + return static_cast(onOutOfMemoryCanGC(js::AllocFunction::Realloc, bytes, p)); } /* From 57abe031dd35524b3ee17c5de0b45454e383ffc1 Mon Sep 17 00:00:00 2001 From: Tom Schuster Date: Tue, 6 Oct 2015 17:04:09 +0100 Subject: [PATCH 174/228] Bug 1188390 - Fail when Sprinter in disassemble ooms. r=h4writer --- js/src/shell/js.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 4897f29003bb..28c03d4b1a2e 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -2094,7 +2094,8 @@ DisassembleToSprinter(JSContext* cx, unsigned argc, Value* vp, Sprinter* sprinte return false; } } - return true; + + return !sprinter->hadOutOfMemory(); } static bool From 9f084aa31c00e639f11ea08ccd5a9d3d7781f687 Mon Sep 17 00:00:00 2001 From: Tom Schuster Date: Tue, 6 Oct 2015 17:04:09 +0100 Subject: [PATCH 175/228] Bug 1211832 - Disable functions that can easily cause artificial OOMs. r=jonco --- js/src/builtin/TestingFunctions.cpp | 20 +++++++++++++++++++- js/src/builtin/TestingFunctions.h | 2 +- js/src/jsapi-tests/testSavedStacks.cpp | 2 +- js/src/jsapi-tests/testUbiNode.cpp | 2 +- js/src/jsfriendapi.cpp | 2 +- js/src/shell/js.cpp | 8 +++++++- 6 files changed, 30 insertions(+), 6 deletions(-) diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 665d9970f6b0..6dc84e513ca4 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -49,6 +49,10 @@ using mozilla::UniquePtr; // fuzzers. Set this via the environment variable MOZ_FUZZING_SAFE. static bool fuzzingSafe = false; +// If disableOOMFunctions is set, disable functionality that causes artificial +// OOM conditions. +static bool disableOOMFunctions = false; + static bool GetBuildConfiguration(JSContext* cx, unsigned argc, Value* vp) { @@ -352,6 +356,11 @@ GCParameter(JSContext* cx, unsigned argc, Value* vp) return false; } + if (disableOOMFunctions && (param == JSGC_MAX_BYTES || param == JSGC_MAX_MALLOC_BYTES)) { + args.rval().setUndefined(); + return true; + } + uint32_t value; if (!ToUint32(cx, args[1], &value)) return false; @@ -996,6 +1005,12 @@ static bool SetupOOMFailure(JSContext* cx, bool failAlways, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); + + if (disableOOMFunctions) { + args.rval().setUndefined(); + return true; + } + if (args.length() < 1) { JS_ReportError(cx, "Count argument required"); return false; @@ -3344,12 +3359,15 @@ static const JSPropertySpec TestingProperties[] = { }; bool -js::DefineTestingFunctions(JSContext* cx, HandleObject obj, bool fuzzingSafe_) +js::DefineTestingFunctions(JSContext* cx, HandleObject obj, bool fuzzingSafe_, + bool disableOOMFunctions_) { fuzzingSafe = fuzzingSafe_; if (getenv("MOZ_FUZZING_SAFE") && getenv("MOZ_FUZZING_SAFE")[0] != '0') fuzzingSafe = true; + disableOOMFunctions = disableOOMFunctions_; + if (!JS_DefineProperties(cx, obj, TestingProperties)) return false; diff --git a/js/src/builtin/TestingFunctions.h b/js/src/builtin/TestingFunctions.h index 5e7a6e1a3b6e..d8fdf2467324 100644 --- a/js/src/builtin/TestingFunctions.h +++ b/js/src/builtin/TestingFunctions.h @@ -12,7 +12,7 @@ namespace js { bool -DefineTestingFunctions(JSContext* cx, HandleObject obj, bool fuzzingSafe); +DefineTestingFunctions(JSContext* cx, HandleObject obj, bool fuzzingSafe, bool disableOOMFunctions); bool testingFunc_assertFloat32(JSContext* cx, unsigned argc, Value* vp); diff --git a/js/src/jsapi-tests/testSavedStacks.cpp b/js/src/jsapi-tests/testSavedStacks.cpp index b1caa6648507..62f6985e7d59 100644 --- a/js/src/jsapi-tests/testSavedStacks.cpp +++ b/js/src/jsapi-tests/testSavedStacks.cpp @@ -66,7 +66,7 @@ END_TEST(testSavedStacks_ApiDefaultValues) BEGIN_TEST(testSavedStacks_RangeBasedForLoops) { - CHECK(js::DefineTestingFunctions(cx, global, false)); + CHECK(js::DefineTestingFunctions(cx, global, false, false)); JS::RootedValue val(cx); CHECK(evaluate("(function one() { \n" // 1 diff --git a/js/src/jsapi-tests/testUbiNode.cpp b/js/src/jsapi-tests/testUbiNode.cpp index 5c66f23bb36d..9457fcc9cb8e 100644 --- a/js/src/jsapi-tests/testUbiNode.cpp +++ b/js/src/jsapi-tests/testUbiNode.cpp @@ -172,7 +172,7 @@ checkString(const char* expected, F fillBufferFunction, G stringGetterFunction) BEGIN_TEST(test_ubiStackFrame) { - CHECK(js::DefineTestingFunctions(cx, global, false)); + CHECK(js::DefineTestingFunctions(cx, global, false, false)); JS::RootedValue val(cx); CHECK(evaluate("(function one() { \n" // 1 diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index 58ddc751a378..0ee94f548fc2 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -1078,7 +1078,7 @@ js::GetTestingFunctions(JSContext* cx) if (!obj) return nullptr; - if (!DefineTestingFunctions(cx, obj, false)) + if (!DefineTestingFunctions(cx, obj, false, false)) return nullptr; return obj; diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 28c03d4b1a2e..f66ae78bfbd0 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -186,6 +186,7 @@ static FILE* gOutFile = nullptr; static bool reportWarnings = true; static bool compileOnly = false; static bool fuzzingSafe = false; +static bool disableOOMFunctions = false; #ifdef DEBUG static bool dumpEntrainedVariables = false; @@ -5781,7 +5782,7 @@ NewGlobalObject(JSContext* cx, JS::CompartmentOptions& options, { return nullptr; } - if (!js::DefineTestingFunctions(cx, glob, fuzzingSafe)) + if (!js::DefineTestingFunctions(cx, glob, fuzzingSafe, disableOOMFunctions)) return nullptr; if (!fuzzingSafe) { @@ -6212,6 +6213,9 @@ Shell(JSContext* cx, OptionParser* op, char** envp) else fuzzingSafe = (getenv("MOZ_FUZZING_SAFE") && getenv("MOZ_FUZZING_SAFE")[0] != '0'); + if (op->getBoolOption("disable-oom-functions")) + disableOOMFunctions = true; + RootedObject glob(cx); JS::CompartmentOptions options; options.setVersion(JSVERSION_LATEST); @@ -6411,6 +6415,8 @@ main(int argc, char** argv, char** envp) || !op.addBoolOption('\0', "no-avx", "No-op. AVX is currently disabled by default.") || !op.addBoolOption('\0', "fuzzing-safe", "Don't expose functions that aren't safe for " "fuzzers to call") + || !op.addBoolOption('\0', "disable-oom-functions", "Disable functions that cause " + "artificial OOMs") || !op.addBoolOption('\0', "no-threads", "Disable helper threads") #ifdef DEBUG || !op.addBoolOption('\0', "dump-entrained-variables", "Print variables which are " From a16944ff6741756c8a82b467e04ff6f8490ce895 Mon Sep 17 00:00:00 2001 From: Ting-Yu Lin Date: Wed, 7 Oct 2015 18:09:03 +0800 Subject: [PATCH 176/228] Bug 1212186 - Disable 'layout.word_select.eat_space_to_next_word' in carets tests. r=mtseng To get the same behavior across all platforms for carets test, disable 'layout.word_select.eat_space_to_next_word'. In this way, we don't need to worry about the spaces being selected on Windows, and those strip() in individual tests can be eliminated. --HG-- extra : commitid : CbqEsabADIl extra : rebase_source : df60d7092ecf95baef64fff4706dd189fbb11b9e --- .../base/tests/marionette/test_selectioncarets.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/layout/base/tests/marionette/test_selectioncarets.py b/layout/base/tests/marionette/test_selectioncarets.py index 233072636179..f46991f2fd59 100644 --- a/layout/base/tests/marionette/test_selectioncarets.py +++ b/layout/base/tests/marionette/test_selectioncarets.py @@ -165,7 +165,7 @@ class CommonCaretsTestCase(object): self.long_press_on_word(el, 0) # Ignore extra spaces selected after the word. - assertFunc(target_content, sel.selected_content.rstrip()) + assertFunc(target_content, sel.selected_content) def _test_move_selection_carets(self, el, assertFunc): sel = SelectionManager(el) @@ -191,8 +191,7 @@ class CommonCaretsTestCase(object): # Move the left caret to the previous position of the right caret. self.actions.flick(el, caret1_x, caret1_y, caret2_x, caret2_y).perform() - # Ignore extra spaces at the beginning of the content in comparison. - assertFunc(target_content.lstrip(), sel.selected_content.lstrip()) + assertFunc(target_content, sel.selected_content) def _test_minimum_select_one_character(self, el, assertFunc, x=None, y=None): @@ -358,7 +357,7 @@ class CommonCaretsTestCase(object): # Drag end caret back to the target word self.actions.flick(self._body, start_caret_x, start_caret_y, caret2_x, caret2_y).perform() - self.assertEqual(self.to_unix_line_ending(sel.selected_content.strip()), 'select') + self.assertEqual(self.to_unix_line_ending(sel.selected_content), 'select') @skip_if_not_rotatable def test_caret_position_after_changing_orientation_of_device(self): @@ -382,7 +381,7 @@ class CommonCaretsTestCase(object): # other tests self.marionette.set_orientation('portrait') - self.assertEqual(self.to_unix_line_ending(sel.selected_content.strip()), 'o') + self.assertEqual(self.to_unix_line_ending(sel.selected_content), 'o') def test_select_word_inside_an_iframe(self): '''Bug 1088552 @@ -404,7 +403,7 @@ class CommonCaretsTestCase(object): self._bottomtext = self.marionette.find_element(By.ID, 'bottomtext') self.long_press_on_location(self._bottomtext) - self.assertNotEqual(self.to_unix_line_ending(sel.selected_content.strip()), '') + self.assertNotEqual(self.to_unix_line_ending(sel.selected_content), '') ######################################################################## # test cases with selection carets enabled @@ -623,9 +622,9 @@ class SelectionCaretsTestCase(CommonCaretsTestCase, MarionetteTestCase): def setUp(self): super(SelectionCaretsTestCase, self).setUp() self.carets_tested_pref = 'selectioncaret.enabled' - self.prefs = { 'layout.accessiblecaret.enabled': False, + 'layout.word_select.eat_space_to_next_word': False, self.carets_tested_pref: True, } self.marionette.set_prefs(self.prefs) @@ -635,9 +634,9 @@ class AccessibleCaretSelectionModeTestCase(CommonCaretsTestCase, MarionetteTestC def setUp(self): super(AccessibleCaretSelectionModeTestCase, self).setUp() self.carets_tested_pref = 'layout.accessiblecaret.enabled' - self.prefs = { 'selectioncaret.enabled': False, + 'layout.word_select.eat_space_to_next_word': False, 'layout.accessiblecaret.use_long_tap_injector': False, self.carets_tested_pref: True, } From 5f39bd27b7caa4e703d2dc7636bce885edba36c6 Mon Sep 17 00:00:00 2001 From: Ting-Yu Lin Date: Wed, 7 Oct 2015 18:09:03 +0800 Subject: [PATCH 177/228] Bug 1207934 - Reset mImaginaryCaretRect if it is out of scrollport. r=roc --HG-- extra : commitid : CbqEsabADIl extra : rebase_source : d3cb8ee74940b5f26cf706f63c8533c7547b2ad5 --- layout/base/AccessibleCaret.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/layout/base/AccessibleCaret.cpp b/layout/base/AccessibleCaret.cpp index e7a7a2ab3d3f..474d079517e8 100644 --- a/layout/base/AccessibleCaret.cpp +++ b/layout/base/AccessibleCaret.cpp @@ -253,6 +253,7 @@ AccessibleCaret::SetPosition(nsIFrame* aFrame, int32_t aOffset) if (imaginaryCaretRectInFrame.IsEmpty()) { // Don't bother to set the caret position since it's invisible. + mImaginaryCaretRect = nsRect(); return PositionChangedResult::Invisible; } From d1b753d12b3f7b0fadbf83f9d4487d9448d18197 Mon Sep 17 00:00:00 2001 From: Ting-Yu Lin Date: Wed, 7 Oct 2015 18:09:03 +0800 Subject: [PATCH 178/228] Bug 1207934 - Fix word_location(). r=automatedtester word_location() did not work if there are multiple spaces between words. We split by \S+ which is non-spaces, so tokens[0] is an space token. Test cases are added to ensure the correctness. --HG-- extra : commitid : CbqEsabADIl extra : rebase_source : 9afccc28c8289244871b3912435a1ee63c3b4c5d --- .../tests/marionette/test_selectioncarets.py | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/layout/base/tests/marionette/test_selectioncarets.py b/layout/base/tests/marionette/test_selectioncarets.py index f46991f2fd59..0939465ceba0 100644 --- a/layout/base/tests/marionette/test_selectioncarets.py +++ b/layout/base/tests/marionette/test_selectioncarets.py @@ -78,6 +78,31 @@ class CommonCaretsTestCase(object): self._iframe = self.marionette.find_element(By.ID, 'frame') + def word_offset(self, text, ordinal): + 'Get the character offset of the ordinal-th word in text.' + tokens = re.split(r'(\S+)', text) # both words and spaces + spaces = tokens[0::2] # collect spaces at odd indices + words = tokens[1::2] # collect word at even indices + + if ordinal >= len(words): + raise IndexError('Only %d words in text, but got ordinal %d' % + (len(words), ordinal)) + + # Cursor position of the targeting word is behind the the first + # character in the word. For example, offset to 'def' in 'abc def' is + # between 'd' and 'e'. + offset = len(spaces[0]) + 1 + offset += sum(len(words[i]) + len(spaces[i + 1]) for i in range(ordinal)) + return offset + + def test_word_offset(self): + text = ' ' * 3 + 'abc' + ' ' * 3 + 'def' + + self.assertTrue(self.word_offset(text, 0), 4) + self.assertTrue(self.word_offset(text, 1), 10) + with self.assertRaises(IndexError): + self.word_offset(text, 2) + def word_location(self, el, ordinal): '''Get the location (x, y) of the ordinal-th word in el. @@ -88,16 +113,7 @@ class CommonCaretsTestCase(object): ''' sel = SelectionManager(el) - tokens = re.split(r'(\S+)', sel.content) # both words and spaces - words = tokens[0::2] # collect words at even indices - spaces = tokens[1::2] # collect spaces at odd indices - self.assertTrue(ordinal < len(words), - 'Expect at least %d words in the content.' % ordinal) - - # Cursor position of the targeting word is behind the the first - # character in the word. For example, offset to 'def' in 'abc def' is - # between 'd' and 'e'. - offset = sum(len(words[i]) + len(spaces[i]) for i in range(ordinal)) + 1 + offset = self.word_offset(sel.content, ordinal) # Move caret to the word. el.tap() From 212c631dea70680069875437f93585da5ef5e1d3 Mon Sep 17 00:00:00 2001 From: Ting-Yu Lin Date: Wed, 7 Oct 2015 18:09:03 +0800 Subject: [PATCH 179/228] Bug 1207934 - Add marionette test for appearance changing. r=automatedtester Test the second carets can still be dragging after its appearance changing from Normal to NormalNotShown then back to Normal again. This test is only for AccessibleCaret, not for SelectionCarets. --HG-- extra : commitid : CbqEsabADIl extra : rebase_source : 7bdf94164c25209c92fc4bd5fa4ae9e83a498bf7 --- .../tests/marionette/test_selectioncarets.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/layout/base/tests/marionette/test_selectioncarets.py b/layout/base/tests/marionette/test_selectioncarets.py index 0939465ceba0..abadf82dcf4f 100644 --- a/layout/base/tests/marionette/test_selectioncarets.py +++ b/layout/base/tests/marionette/test_selectioncarets.py @@ -657,3 +657,39 @@ class AccessibleCaretSelectionModeTestCase(CommonCaretsTestCase, MarionetteTestC self.carets_tested_pref: True, } self.marionette.set_prefs(self.prefs) + + def test_long_press_to_select_when_partial_visible_word_is_selected(self): + self.open_test_html() + el = self._input + sel = SelectionManager(el) + + # To successfully select the second word while the first word is being + # selected, use sufficient spaces between 'a' and 'b' to avoid the + # second caret covers on the second word. + original_content = 'aaaaaaaa bbbbbbbb' + el.clear() + el.send_keys(original_content) + words = original_content.split() + + # We cannot use self.long_press_on_word() directly since it has will + # change the cursor position which affects this test. We have to store + # the position of word 0 and word 1 before long-pressing to select the + # word. + word0_x, word0_y = self.word_location(el, 0) + word1_x, word1_y = self.word_location(el, 1) + + self.long_press_on_location(el, word0_x, word0_y) + self.assertEqual(words[0], sel.selected_content) + + self.long_press_on_location(el, word1_x, word1_y) + self.assertEqual(words[1], sel.selected_content) + + self.long_press_on_location(el, word0_x, word0_y) + self.assertEqual(words[0], sel.selected_content) + + # If the second carets is visible, it can be dragged to the position of + # the first caret. After that, selection will contain only the first + # character. + (caret1_x, caret1_y), (caret2_x, caret2_y) = sel.selection_carets_location() + self.actions.flick(el, caret2_x, caret2_y, caret1_x, caret1_y).perform() + self.assertEqual(words[0][0], sel.selected_content) From 23e9bd9f77da1c54a4f3feb63928e050d04cb2d2 Mon Sep 17 00:00:00 2001 From: Ting-Yu Lin Date: Wed, 7 Oct 2015 18:09:04 +0800 Subject: [PATCH 180/228] Bug 1200364 - Fix AccessibleCaret jumps when dragging. r=roc TouchCaret does not have this issue since it clamps the dragging point to the editable content boundary. Fix this bug by porting TouchCaret::GetContentBoundary() to AccessibleCaret. I apply the clamp logic to both cursor mode and selection mode if the focus node is on an editable content, which makes carets dragging in selection mode smoother than SelectionCarets. --HG-- extra : commitid : CbqEsabADIl extra : rebase_source : 86847ced02859cd556806d547461e8f4167eab73 --- layout/base/AccessibleCaretManager.cpp | 52 ++++++++++++++++--- layout/base/AccessibleCaretManager.h | 10 ++++ .../tests/marionette/test_selectioncarets.py | 23 ++++++++ .../base/tests/marionette/test_touchcaret.py | 19 +++++++ 4 files changed, 97 insertions(+), 7 deletions(-) diff --git a/layout/base/AccessibleCaretManager.cpp b/layout/base/AccessibleCaretManager.cpp index abedeb47faa6..c939de383831 100644 --- a/layout/base/AccessibleCaretManager.cpp +++ b/layout/base/AccessibleCaretManager.cpp @@ -908,19 +908,57 @@ AccessibleCaretManager::DragCaretInternal(const nsPoint& aPoint) return NS_OK; } +nsRect +AccessibleCaretManager::GetContentBoundaryForFrame(nsIFrame* aFrame) const +{ + nsRect resultRect; + nsIFrame* rootFrame = mPresShell->GetRootFrame(); + + for (; aFrame; aFrame = aFrame->GetNextContinuation()) { + nsRect rect = aFrame->GetContentRectRelativeToSelf(); + nsLayoutUtils::TransformRect(aFrame, rootFrame, rect); + resultRect = resultRect.Union(rect); + + nsIFrame::ChildListIterator lists(aFrame); + for (; !lists.IsDone(); lists.Next()) { + // Loop over all children to take the overflow rect into consideration. + for (nsIFrame* child : lists.CurrentList()) { + nsRect overflowRect = child->GetScrollableOverflowRect(); + nsLayoutUtils::TransformRect(child, rootFrame, overflowRect); + resultRect = resultRect.Union(overflowRect); + } + } + } + + // Shrink rect to make sure we never hit the boundary. + resultRect.Deflate(kBoundaryAppUnits); + return resultRect; +} + nsPoint AccessibleCaretManager::AdjustDragBoundary(const nsPoint& aPoint) const { - // Bug 1068474: Adjust the Y-coordinate so that the carets won't be in tilt - // mode when a caret is being dragged surpass the other caret. - // - // For example, when dragging the second caret, the horizontal boundary (lower - // bound) of its Y-coordinate is the logical position of the first caret. - // Likewise, when dragging the first caret, the horizontal boundary (upper - // bound) of its Y-coordinate is the logical position of the second caret. nsPoint adjustedPoint = aPoint; + int32_t focusOffset = 0; + nsIFrame* focusFrame = + nsCaret::GetFrameAndOffset(GetSelection(), nullptr, 0, &focusOffset); + Element* editingHost = GetEditingHostForFrame(focusFrame); + + if (editingHost) { + nsRect boundary = + GetContentBoundaryForFrame(editingHost->GetPrimaryFrame()); + adjustedPoint = boundary.ClampPoint(adjustedPoint); + } + if (GetCaretMode() == CaretMode::Selection) { + // Bug 1068474: Adjust the Y-coordinate so that the carets won't be in tilt + // mode when a caret is being dragged surpass the other caret. + // + // For example, when dragging the second caret, the horizontal boundary (lower + // bound) of its Y-coordinate is the logical position of the first caret. + // Likewise, when dragging the first caret, the horizontal boundary (upper + // bound) of its Y-coordinate is the logical position of the second caret. if (mActiveCaret == mFirstCaret.get()) { nscoord dragDownBoundaryY = mSecondCaret->LogicalPosition().y; if (dragDownBoundaryY > 0 && adjustedPoint.y > dragDownBoundaryY) { diff --git a/layout/base/AccessibleCaretManager.h b/layout/base/AccessibleCaretManager.h index 69a0acac826d..2fc314c90764 100644 --- a/layout/base/AccessibleCaretManager.h +++ b/layout/base/AccessibleCaretManager.h @@ -156,6 +156,10 @@ protected: dom::Selection* GetSelection() const; already_AddRefed GetFrameSelection() const; + // Get the bounding rectangle for aFrame where the caret under cursor mode can + // be positioned. The rectangle is relative to the root frame. + nsRect GetContentBoundaryForFrame(nsIFrame* aFrame) const; + // If we're dragging the first caret, we do not want to drag it over the // previous character of the second caret. Same as the second caret. So we // check if content offset exceeds the previous/next character of second/first @@ -222,6 +226,12 @@ protected: CaretMode mLastUpdateCaretMode = CaretMode::None; static const int32_t kAutoScrollTimerDelay = 30; + + // Clicking on the boundary of input or textarea will move the caret to the + // front or end of the content. To avoid this, we need to deflate the content + // boundary by 61 app units, which is 1 pixel + 1 app unit as defined in + // AppUnit.h. + static const int32_t kBoundaryAppUnits = 61; }; std::ostream& operator<<(std::ostream& aStream, diff --git a/layout/base/tests/marionette/test_selectioncarets.py b/layout/base/tests/marionette/test_selectioncarets.py index abadf82dcf4f..5ab1c7abc736 100644 --- a/layout/base/tests/marionette/test_selectioncarets.py +++ b/layout/base/tests/marionette/test_selectioncarets.py @@ -693,3 +693,26 @@ class AccessibleCaretSelectionModeTestCase(CommonCaretsTestCase, MarionetteTestC (caret1_x, caret1_y), (caret2_x, caret2_y) = sel.selection_carets_location() self.actions.flick(el, caret2_x, caret2_y, caret1_x, caret1_y).perform() self.assertEqual(words[0][0], sel.selected_content) + + def test_carets_do_not_jump_when_dragging_to_editable_content_boundary(self): + self.open_test_html() + el = self._input + sel = SelectionManager(el) + original_content = sel.content + words = original_content.split() + self.assertTrue(len(words) >= 3, 'Expect at least three words in the content.') + + # Goal: the selection does not being changed after dragging the caret + # on the Y-axis only. + target_content = words[1] + + self.long_press_on_word(el, 1) + (caret1_x, caret1_y), (caret2_x, caret2_y) = sel.selection_carets_location() + + # Drag the first caret up by 50px. + self.actions.flick(el, caret1_x, caret1_y, caret1_x, caret1_y - 50).perform() + self.assertEqual(target_content, sel.selected_content) + + # Drag the first caret down by 50px. + self.actions.flick(el, caret2_x, caret2_y, caret2_x, caret2_y + 50).perform() + self.assertEqual(target_content, sel.selected_content) diff --git a/layout/base/tests/marionette/test_touchcaret.py b/layout/base/tests/marionette/test_touchcaret.py index 09b6e63c8711..cdaa663c0222 100644 --- a/layout/base/tests/marionette/test_touchcaret.py +++ b/layout/base/tests/marionette/test_touchcaret.py @@ -334,3 +334,22 @@ class AccessibleCaretCursorModeTestCase(CommonCaretTestCase, MarionetteTestCase) self.caret_timeout_ms_pref: 0, } self.marionette.set_prefs(self.prefs) + + def test_caret_does_not_jump_when_dragging_to_editable_content_boundary(self): + self.open_test_html() + el = self._input + sel = SelectionManager(el) + content_to_add = '!' + non_target_content = sel.content + content_to_add + + # Goal: the cursor position does not being changed after dragging the + # caret down on the Y-axis. + el.tap() + sel.move_caret_to_front() + el.tap(*sel.caret_location()) + x, y = sel.touch_caret_location() + + # Drag the caret down by 50px, and insert '!'. + self.actions.flick(el, x, y, x, y + 50).perform() + self.actions.key_down(content_to_add).key_up(content_to_add).perform() + self.assertNotEqual(non_target_content, sel.content) From c3ced0a78ee745fdbff9fb07e940956df971fbf9 Mon Sep 17 00:00:00 2001 From: Tim Taubert Date: Fri, 11 Sep 2015 16:01:20 +0200 Subject: [PATCH 181/228] Bug 1001691 - Implement WebCrypto thread pool r=bz --- dom/crypto/WebCryptoThreadPool.cpp | 117 +++++++++++++++++++++++++++++ dom/crypto/WebCryptoThreadPool.h | 54 +++++++++++++ dom/crypto/moz.build | 3 + layout/build/nsLayoutStatics.cpp | 3 + 4 files changed, 177 insertions(+) create mode 100644 dom/crypto/WebCryptoThreadPool.cpp create mode 100644 dom/crypto/WebCryptoThreadPool.h diff --git a/dom/crypto/WebCryptoThreadPool.cpp b/dom/crypto/WebCryptoThreadPool.cpp new file mode 100644 index 000000000000..3abe347ddee1 --- /dev/null +++ b/dom/crypto/WebCryptoThreadPool.cpp @@ -0,0 +1,117 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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/dom/WebCryptoThreadPool.h" + +#include "mozilla/Services.h" +#include "mozilla/StaticPtr.h" +#include "nsComponentManagerUtils.h" +#include "nsXPCOMCIDInternal.h" +#include "nsXPCOMPrivate.h" +#include "nsIObserverService.h" +#include "nsIThreadPool.h" + +namespace mozilla { +namespace dom { + +StaticRefPtr gInstance; + +NS_IMPL_ISUPPORTS(WebCryptoThreadPool, nsIObserver) + +/* static */ void +WebCryptoThreadPool::Initialize() +{ + MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); + MOZ_ASSERT(!gInstance, "More than one instance!"); + + gInstance = new WebCryptoThreadPool(); + NS_WARN_IF_FALSE(gInstance, "Failed create thread pool!"); + + if (gInstance && NS_FAILED(gInstance->Init())) { + NS_WARNING("Failed to initialize thread pool!"); + gInstance = nullptr; + } +} + +/* static */ nsresult +WebCryptoThreadPool::Dispatch(nsIRunnable* aRunnable) +{ + if (gInstance) { + return gInstance->DispatchInternal(aRunnable); + } + + // Fail if called on shutdown. + return NS_ERROR_FAILURE; +} + +nsresult +WebCryptoThreadPool::Init() +{ + MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); + + nsCOMPtr obs = mozilla::services::GetObserverService(); + NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE); + + // Need this observer to know when to shut down the thread pool. + return obs->AddObserver(this, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false); +} + +nsresult +WebCryptoThreadPool::DispatchInternal(nsIRunnable* aRunnable) +{ + MutexAutoLock lock(mMutex); + + if (!mPool) { + nsCOMPtr pool(do_CreateInstance(NS_THREADPOOL_CONTRACTID)); + NS_ENSURE_TRUE(pool, NS_ERROR_FAILURE); + + nsresult rv = pool->SetName(NS_LITERAL_CSTRING("SubtleCrypto")); + NS_ENSURE_SUCCESS(rv, rv); + + pool.swap(mPool); + } + + return mPool->Dispatch(aRunnable, NS_DISPATCH_NORMAL); +} + +void +WebCryptoThreadPool::Shutdown() +{ + MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); + MutexAutoLock lock(mMutex); + + if (mPool) { + mPool->Shutdown(); + } + + nsCOMPtr obs = mozilla::services::GetObserverService(); + NS_WARN_IF_FALSE(obs, "Failed to retrieve observer service!"); + + if (obs) { + if (NS_FAILED(obs->RemoveObserver(this, + NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID))) { + NS_WARNING("Failed to remove shutdown observer!"); + } + } +} + +NS_IMETHODIMP +WebCryptoThreadPool::Observe(nsISupports* aSubject, + const char* aTopic, + const char16_t* aData) +{ + MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); + + if (gInstance) { + gInstance->Shutdown(); + gInstance = nullptr; + } + + return NS_OK; +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/crypto/WebCryptoThreadPool.h b/dom/crypto/WebCryptoThreadPool.h new file mode 100644 index 000000000000..e6f0f2fb1639 --- /dev/null +++ b/dom/crypto/WebCryptoThreadPool.h @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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_dom_WebCryptoThreadPool_h +#define mozilla_dom_WebCryptoThreadPool_h + +#include "nsIObserverService.h" +#include "nsIThreadPool.h" + +namespace mozilla { +namespace dom { + +class WebCryptoThreadPool final : nsIObserver { +public: + NS_DECL_THREADSAFE_ISUPPORTS + + static void + Initialize(); + + static nsresult + Dispatch(nsIRunnable* aRunnable); + +private: + WebCryptoThreadPool() + : mMutex("WebCryptoThreadPool::mMutex") + , mPool(nullptr) + { } + virtual ~WebCryptoThreadPool() + { } + + nsresult + Init(); + + nsresult + DispatchInternal(nsIRunnable* aRunnable); + + void + Shutdown(); + + NS_IMETHODIMP Observe(nsISupports* aSubject, + const char* aTopic, + const char16_t* aData) override; + + mozilla::Mutex mMutex; + nsCOMPtr mPool; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_WebCryptoThreadPool_h diff --git a/dom/crypto/moz.build b/dom/crypto/moz.build index 59381c383705..6097ccd3f2b1 100644 --- a/dom/crypto/moz.build +++ b/dom/crypto/moz.build @@ -10,6 +10,7 @@ EXPORTS.mozilla.dom += [ 'KeyAlgorithmProxy.h', 'WebCryptoCommon.h', 'WebCryptoTask.h', + 'WebCryptoThreadPool.h' ] UNIFIED_SOURCES += [ @@ -17,6 +18,7 @@ UNIFIED_SOURCES += [ 'CryptoKey.cpp', 'KeyAlgorithmProxy.cpp', 'WebCryptoTask.cpp', + 'WebCryptoThreadPool.cpp', ] include('/ipc/chromium/chromium-config.mozbuild') @@ -26,6 +28,7 @@ FINAL_LIBRARY = 'xul' LOCAL_INCLUDES += [ '/security/manager/ssl', '/security/pkix/include', + '/xpcom/build', ] MOCHITEST_MANIFESTS += ['test/mochitest.ini'] diff --git a/layout/build/nsLayoutStatics.cpp b/layout/build/nsLayoutStatics.cpp index 6841040ccd97..0d2933954386 100644 --- a/layout/build/nsLayoutStatics.cpp +++ b/layout/build/nsLayoutStatics.cpp @@ -73,6 +73,7 @@ #include "AudioChannelService.h" #include "mozilla/dom/DataStoreService.h" #include "mozilla/dom/PromiseDebugging.h" +#include "mozilla/dom/WebCryptoThreadPool.h" #ifdef MOZ_XUL #include "nsXULPopupManager.h" @@ -323,6 +324,8 @@ nsLayoutStatics::Initialize() mozilla::dom::devicestorage::DeviceStorageStatics::Initialize(); + mozilla::dom::WebCryptoThreadPool::Initialize(); + return NS_OK; } From 8f64c093bfaab048395c3635167ec201bc2c9316 Mon Sep 17 00:00:00 2001 From: Tim Taubert Date: Fri, 11 Sep 2015 23:41:58 +0200 Subject: [PATCH 182/228] Bug 1001691 - Use thread pool for WebCrypto operations r=bz --- dom/crypto/WebCryptoTask.cpp | 71 ++++++++++++++++++++++++++++++++++-- dom/crypto/WebCryptoTask.h | 71 +++++++++++++++++++++++------------- 2 files changed, 113 insertions(+), 29 deletions(-) diff --git a/dom/crypto/WebCryptoTask.cpp b/dom/crypto/WebCryptoTask.cpp index a347e4e72afa..2519f3b005dc 100644 --- a/dom/crypto/WebCryptoTask.cpp +++ b/dom/crypto/WebCryptoTask.cpp @@ -8,6 +8,7 @@ #include "cryptohi.h" #include "secerr.h" #include "ScopedNSSTypes.h" +#include "nsNSSComponent.h" #include "jsapi.h" #include "mozilla/Telemetry.h" @@ -17,6 +18,7 @@ #include "mozilla/dom/TypedArray.h" #include "mozilla/dom/WebCryptoCommon.h" #include "mozilla/dom/WebCryptoTask.h" +#include "mozilla/dom/WebCryptoThreadPool.h" namespace mozilla { namespace dom { @@ -286,9 +288,72 @@ CloneData(JSContext* aCx, CryptoBuffer& aDst, JS::Handle aSrc) // Implementation of WebCryptoTask methods void -WebCryptoTask::FailWithError(nsresult aRv) +WebCryptoTask::DispatchWithPromise(Promise* aResultPromise) { MOZ_ASSERT(NS_IsMainThread()); + mResultPromise = aResultPromise; + + // Fail if an error was set during the constructor + MAYBE_EARLY_FAIL(mEarlyRv) + + // Perform pre-NSS operations, and fail if they fail + mEarlyRv = BeforeCrypto(); + MAYBE_EARLY_FAIL(mEarlyRv) + + // Skip NSS if we're already done, or launch a CryptoTask + if (mEarlyComplete) { + CallCallback(mEarlyRv); + Skip(); + return; + } + + // Ensure that NSS is initialized, since presumably CalculateResult + // will use NSS functions + if (!EnsureNSSInitializedChromeOrContent()) { + mEarlyRv = NS_ERROR_DOM_UNKNOWN_ERR; + MAYBE_EARLY_FAIL(mEarlyRv) + } + + // Store calling thread and dispatch to thread pool. + mOriginalThread = NS_GetCurrentThread(); + mEarlyRv = WebCryptoThreadPool::Dispatch(this); + MAYBE_EARLY_FAIL(mEarlyRv) +} + +NS_IMETHODIMP +WebCryptoTask::Run() +{ + // Run heavy crypto operations on the thread pool, off the original thread. + if (!IsOnOriginalThread()) { + nsNSSShutDownPreventionLock locker; + + if (isAlreadyShutDown()) { + mRv = NS_ERROR_NOT_AVAILABLE; + } else { + mRv = CalculateResult(); + } + + // Back to the original thread, i.e. continue below. + mOriginalThread->Dispatch(this, NS_DISPATCH_NORMAL); + return NS_OK; + } + + // We're now back on the calling thread. + + // Release NSS resources now, before calling CallCallback, so that + // WebCryptoTasks have consistent behavior regardless of whether NSS is shut + // down between CalculateResult being called and CallCallback being called. + virtualDestroyNSSReference(); + + CallCallback(mRv); + + return NS_OK; +} + +void +WebCryptoTask::FailWithError(nsresult aRv) +{ + MOZ_ASSERT(IsOnOriginalThread()); Telemetry::Accumulate(Telemetry::WEBCRYPTO_RESOLVED, false); // Blindly convert nsresult to DOMException @@ -302,7 +367,7 @@ WebCryptoTask::FailWithError(nsresult aRv) nsresult WebCryptoTask::CalculateResult() { - MOZ_ASSERT(!NS_IsMainThread()); + MOZ_ASSERT(!IsOnOriginalThread()); if (isAlreadyShutDown()) { return NS_ERROR_DOM_UNKNOWN_ERR; @@ -314,7 +379,7 @@ WebCryptoTask::CalculateResult() void WebCryptoTask::CallCallback(nsresult rv) { - MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(IsOnOriginalThread()); if (NS_FAILED(rv)) { FailWithError(rv); return; diff --git a/dom/crypto/WebCryptoTask.h b/dom/crypto/WebCryptoTask.h index 67521ee8d131..7e59e75ad2b4 100644 --- a/dom/crypto/WebCryptoTask.h +++ b/dom/crypto/WebCryptoTask.h @@ -7,8 +7,7 @@ #ifndef mozilla_dom_WebCryptoTask_h #define mozilla_dom_WebCryptoTask_h -#include "CryptoTask.h" - +#include "nsNSSShutDown.h" #include "nsIGlobalObject.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/DOMException.h" @@ -58,30 +57,15 @@ if (NS_FAILED(rv)) { \ return; \ } -class WebCryptoTask : public CryptoTask +class WebCryptoTask : public nsCancelableRunnable, + public nsNSSShutDownObject { public: - virtual void DispatchWithPromise(Promise* aResultPromise) + virtual void DispatchWithPromise(Promise* aResultPromise); + + void Skip() { - MOZ_ASSERT(NS_IsMainThread()); - mResultPromise = aResultPromise; - - // Fail if an error was set during the constructor - MAYBE_EARLY_FAIL(mEarlyRv) - - // Perform pre-NSS operations, and fail if they fail - mEarlyRv = BeforeCrypto(); - MAYBE_EARLY_FAIL(mEarlyRv) - - // Skip NSS if we're already done, or launch a CryptoTask - if (mEarlyComplete) { - CallCallback(mEarlyRv); - Skip(); - return; - } - - mEarlyRv = Dispatch("SubtleCrypto"); - MAYBE_EARLY_FAIL(mEarlyRv) + virtualDestroyNSSReference(); } protected: @@ -184,8 +168,25 @@ protected: WebCryptoTask() : mEarlyRv(NS_OK) , mEarlyComplete(false) + , mOriginalThread(nullptr) + , mReleasedNSSResources(false) + , mRv(NS_ERROR_NOT_INITIALIZED) {} + virtual ~WebCryptoTask() + { + MOZ_ASSERT(mReleasedNSSResources); + + nsNSSShutDownPreventionLock lock; + if (!isAlreadyShutDown()) { + shutdown(calledFromObject); + } + } + + bool IsOnOriginalThread() { + return !mOriginalThread || NS_GetCurrentThread() == mOriginalThread; + } + // For things that need to happen on the main thread // either before or after CalculateResult virtual nsresult BeforeCrypto() { return NS_OK; } @@ -198,11 +199,29 @@ protected: // Subclasses should override this method if they keep references to // any NSS objects, e.g., SECKEYPrivateKey or PK11SymKey. - virtual void ReleaseNSSResources() override {} + virtual void ReleaseNSSResources() {} - virtual nsresult CalculateResult() override final; + virtual nsresult CalculateResult() final; - virtual void CallCallback(nsresult rv) override final; + virtual void CallCallback(nsresult rv) final; + +private: + NS_IMETHOD Run() override final; + + virtual void + virtualDestroyNSSReference() override final + { + MOZ_ASSERT(IsOnOriginalThread()); + + if (!mReleasedNSSResources) { + mReleasedNSSResources = true; + ReleaseNSSResources(); + } + } + + nsCOMPtr mOriginalThread; + bool mReleasedNSSResources; + nsresult mRv; }; // XXX This class is declared here (unlike others) to enable reuse by WebRTC. From cd6157491d94690afdae769d4cc2a8d7a76c6f77 Mon Sep 17 00:00:00 2001 From: Tim Taubert Date: Mon, 21 Sep 2015 14:52:40 +0200 Subject: [PATCH 183/228] Bug 1001691 - Make GenerateAsymmetricKeyTask::mKeyPair a UniquePtr so that we can explicitly release it on the main thread r=mt --- dom/crypto/WebCryptoTask.cpp | 79 ++++++++++++++++------------- dom/crypto/WebCryptoTask.h | 3 +- dom/media/webrtc/RTCCertificate.cpp | 6 +-- 3 files changed, 49 insertions(+), 39 deletions(-) diff --git a/dom/crypto/WebCryptoTask.cpp b/dom/crypto/WebCryptoTask.cpp index 2519f3b005dc..f0ebf7546e2c 100644 --- a/dom/crypto/WebCryptoTask.cpp +++ b/dom/crypto/WebCryptoTask.cpp @@ -2256,6 +2256,7 @@ private: GenerateAsymmetricKeyTask::GenerateAsymmetricKeyTask( JSContext* aCx, const ObjectOrString& aAlgorithm, bool aExtractable, const Sequence& aKeyUsages) + : mKeyPair(new CryptoKeyPair()) { nsIGlobalObject* global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx)); if (!global) { @@ -2269,9 +2270,9 @@ GenerateAsymmetricKeyTask::GenerateAsymmetricKeyTask( return; } - // Create an empty key and set easy attributes - mKeyPair.mPrivateKey = new CryptoKey(global); - mKeyPair.mPublicKey = new CryptoKey(global); + // Create an empty key pair and set easy attributes + mKeyPair->mPrivateKey = new CryptoKey(global); + mKeyPair->mPublicKey = new CryptoKey(global); // Extract algorithm name mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, mAlgName); @@ -2303,20 +2304,20 @@ GenerateAsymmetricKeyTask::GenerateAsymmetricKeyTask( } // Create algorithm - if (!mKeyPair.mPublicKey.get()->Algorithm().MakeRsa(mAlgName, - modulusLength, - publicExponent, - hashName)) { - mEarlyRv = NS_ERROR_DOM_OPERATION_ERR; - return; - } - if (!mKeyPair.mPrivateKey.get()->Algorithm().MakeRsa(mAlgName, + if (!mKeyPair->mPublicKey.get()->Algorithm().MakeRsa(mAlgName, modulusLength, publicExponent, hashName)) { mEarlyRv = NS_ERROR_DOM_OPERATION_ERR; return; } + if (!mKeyPair->mPrivateKey.get()->Algorithm().MakeRsa(mAlgName, + modulusLength, + publicExponent, + hashName)) { + mEarlyRv = NS_ERROR_DOM_OPERATION_ERR; + return; + } mMechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; // Set up params struct @@ -2341,8 +2342,8 @@ GenerateAsymmetricKeyTask::GenerateAsymmetricKeyTask( } // Create algorithm. - mKeyPair.mPublicKey.get()->Algorithm().MakeEc(mAlgName, mNamedCurve); - mKeyPair.mPrivateKey.get()->Algorithm().MakeEc(mAlgName, mNamedCurve); + mKeyPair->mPublicKey.get()->Algorithm().MakeEc(mAlgName, mNamedCurve); + mKeyPair->mPrivateKey.get()->Algorithm().MakeEc(mAlgName, mNamedCurve); mMechanism = CKM_EC_KEY_PAIR_GEN; } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_DH)) { RootedDictionary params(aCx); @@ -2366,15 +2367,15 @@ GenerateAsymmetricKeyTask::GenerateAsymmetricKeyTask( } // Create algorithm. - if (!mKeyPair.mPublicKey.get()->Algorithm().MakeDh(mAlgName, - prime, - generator)) { + if (!mKeyPair->mPublicKey.get()->Algorithm().MakeDh(mAlgName, + prime, + generator)) { mEarlyRv = NS_ERROR_DOM_OPERATION_ERR; return; } - if (!mKeyPair.mPrivateKey.get()->Algorithm().MakeDh(mAlgName, - prime, - generator)) { + if (!mKeyPair->mPrivateKey.get()->Algorithm().MakeDh(mAlgName, + prime, + generator)) { mEarlyRv = NS_ERROR_DOM_OPERATION_ERR; return; } @@ -2398,31 +2399,31 @@ GenerateAsymmetricKeyTask::GenerateAsymmetricKeyTask( publicAllowedUsages = 0; } - mKeyPair.mPrivateKey.get()->SetExtractable(aExtractable); - mKeyPair.mPrivateKey.get()->SetType(CryptoKey::PRIVATE); + mKeyPair->mPrivateKey.get()->SetExtractable(aExtractable); + mKeyPair->mPrivateKey.get()->SetType(CryptoKey::PRIVATE); - mKeyPair.mPublicKey.get()->SetExtractable(true); - mKeyPair.mPublicKey.get()->SetType(CryptoKey::PUBLIC); + mKeyPair->mPublicKey.get()->SetExtractable(true); + mKeyPair->mPublicKey.get()->SetType(CryptoKey::PUBLIC); - mKeyPair.mPrivateKey.get()->ClearUsages(); - mKeyPair.mPublicKey.get()->ClearUsages(); + mKeyPair->mPrivateKey.get()->ClearUsages(); + mKeyPair->mPublicKey.get()->ClearUsages(); for (uint32_t i=0; i < aKeyUsages.Length(); ++i) { - mEarlyRv = mKeyPair.mPrivateKey.get()->AddUsageIntersecting(aKeyUsages[i], - privateAllowedUsages); + mEarlyRv = mKeyPair->mPrivateKey.get()->AddUsageIntersecting(aKeyUsages[i], + privateAllowedUsages); if (NS_FAILED(mEarlyRv)) { return; } - mEarlyRv = mKeyPair.mPublicKey.get()->AddUsageIntersecting(aKeyUsages[i], - publicAllowedUsages); + mEarlyRv = mKeyPair->mPublicKey.get()->AddUsageIntersecting(aKeyUsages[i], + publicAllowedUsages); if (NS_FAILED(mEarlyRv)) { return; } } // If no usages ended up being allowed, DataError - if (!mKeyPair.mPublicKey.get()->HasAnyUsage() && - !mKeyPair.mPrivateKey.get()->HasAnyUsage()) { + if (!mKeyPair->mPublicKey.get()->HasAnyUsage() && + !mKeyPair->mPrivateKey.get()->HasAnyUsage()) { mEarlyRv = NS_ERROR_DOM_DATA_ERR; return; } @@ -2438,6 +2439,8 @@ GenerateAsymmetricKeyTask::ReleaseNSSResources() nsresult GenerateAsymmetricKeyTask::DoCrypto() { + MOZ_ASSERT(mKeyPair); + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); MOZ_ASSERT(slot.get()); @@ -2468,15 +2471,15 @@ GenerateAsymmetricKeyTask::DoCrypto() return NS_ERROR_DOM_UNKNOWN_ERR; } - nsresult rv = mKeyPair.mPrivateKey.get()->SetPrivateKey(mPrivateKey); + nsresult rv = mKeyPair->mPrivateKey.get()->SetPrivateKey(mPrivateKey); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR); - rv = mKeyPair.mPublicKey.get()->SetPublicKey(mPublicKey); + rv = mKeyPair->mPublicKey.get()->SetPublicKey(mPublicKey); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR); // PK11_GenerateKeyPair() does not set a CKA_EC_POINT attribute on the // private key, we need this later when exporting to PKCS8 and JWK though. if (mMechanism == CKM_EC_KEY_PAIR_GEN) { - rv = mKeyPair.mPrivateKey->AddPublicKeyData(mPublicKey); + rv = mKeyPair->mPrivateKey->AddPublicKeyData(mPublicKey); NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR); } @@ -2486,7 +2489,13 @@ GenerateAsymmetricKeyTask::DoCrypto() void GenerateAsymmetricKeyTask::Resolve() { - mResultPromise->MaybeResolve(mKeyPair); + mResultPromise->MaybeResolve(*mKeyPair); +} + +void +GenerateAsymmetricKeyTask::Cleanup() +{ + mKeyPair = nullptr; } class DerivePbkdfBitsTask : public ReturnArrayBufferViewTask diff --git a/dom/crypto/WebCryptoTask.h b/dom/crypto/WebCryptoTask.h index 7e59e75ad2b4..e677e1074126 100644 --- a/dom/crypto/WebCryptoTask.h +++ b/dom/crypto/WebCryptoTask.h @@ -233,7 +233,7 @@ public: const Sequence& aKeyUsages); protected: ScopedPLArenaPool mArena; - CryptoKeyPair mKeyPair; + UniquePtr mKeyPair; nsString mAlgName; CK_MECHANISM_TYPE mMechanism; PK11RSAGenParams mRsaParams; @@ -243,6 +243,7 @@ protected: virtual void ReleaseNSSResources() override; virtual nsresult DoCrypto() override; virtual void Resolve() override; + virtual void Cleanup() override; private: ScopedSECKEYPublicKey mPublicKey; diff --git a/dom/media/webrtc/RTCCertificate.cpp b/dom/media/webrtc/RTCCertificate.cpp index 93686d340fa0..45eaa3d0be01 100644 --- a/dom/media/webrtc/RTCCertificate.cpp +++ b/dom/media/webrtc/RTCCertificate.cpp @@ -112,7 +112,7 @@ private: return NS_ERROR_DOM_UNKNOWN_ERR; } - ScopedSECKEYPublicKey publicKey(mKeyPair.mPublicKey.get()->GetPublicKey()); + ScopedSECKEYPublicKey publicKey(mKeyPair->mPublicKey.get()->GetPublicKey()); ScopedCERTSubjectPublicKeyInfo spki( SECKEY_CreateSubjectPublicKeyInfo(publicKey)); if (!spki) { @@ -180,7 +180,7 @@ private: return NS_ERROR_DOM_UNKNOWN_ERR; } - ScopedSECKEYPrivateKey privateKey(mKeyPair.mPrivateKey.get()->GetPrivateKey()); + ScopedSECKEYPrivateKey privateKey(mKeyPair->mPrivateKey.get()->GetPrivateKey()); rv = SEC_DerSignData(arena, signedCert, innerDER.data, innerDER.len, privateKey, mSignatureAlg); if (rv != SECSuccess) { @@ -232,7 +232,7 @@ private: { // Make copies of the private key and certificate, otherwise, when this // object is deleted, the structures they reference will be deleted too. - SECKEYPrivateKey* key = mKeyPair.mPrivateKey.get()->GetPrivateKey(); + SECKEYPrivateKey* key = mKeyPair->mPrivateKey.get()->GetPrivateKey(); CERTCertificate* cert = CERT_DupCertificate(mCertificate); nsRefPtr result = new RTCCertificate(mResultPromise->GetParentObject(), From e7ef778c9dc04d680c14263ece0e3b423b3e6d09 Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Wed, 7 Oct 2015 12:13:45 +0200 Subject: [PATCH 184/228] Backed out 1 changesets (bug 1202902) for causing merge conflicts to mozilla-central Backed out changeset cfc1820361f5 (bug 1202902) --HG-- extra : rebase_source : 5d3db72337754bc7ab0ed0c30b2896100411ff92 --- accessible/tests/mochitest/jsat/dom_helper.js | 4 ++-- accessible/tests/mochitest/jsat/output.js | 2 +- addon-sdk/source/modules/system/Startup.js | 2 +- .../cuddlefish/mobile-utils/bootstrap.js | 2 +- b2g/chrome/content/settings.js | 8 ++++---- b2g/chrome/content/shell.js | 2 +- b2g/chrome/content/shell_remote.js | 4 ++-- .../mochitest/RecordingStatusChromeScript.js | 2 +- b2g/components/MultiscreenHandler.jsm | 4 ++-- .../filepicker_path_handler_chrome.js | 4 ++-- .../mochitest/permission_handler_chrome.js | 6 +++--- .../presentation_prompt_handler_chrome.js | 2 +- .../presentation_ui_glue_handler_chrome.js | 2 +- .../test/mochitest/screenshot_helper.js | 4 ++-- .../test/mochitest/systemapp_helper.js | 2 +- b2g/components/test/unit/file_killswitch.js | 2 +- b2g/components/test/unit/head_identity.js | 4 ++-- .../test/unit/head_logshake_gonk.js | 6 +++--- .../test/unit/test_aboutserviceworkers.js | 2 +- b2g/components/test/unit/test_fxaccounts.js | 2 +- b2g/components/test/unit/test_killswitch.js | 2 +- b2g/components/test/unit/test_logparser.js | 2 +- b2g/components/test/unit/test_logshake.js | 2 +- b2g/simulator/bootstrap.js | 4 ++-- .../content/aboutaccounts/aboutaccounts.js | 2 +- .../content/abouthealthreport/abouthealth.js | 2 +- browser/base/content/pageinfo/pageInfo.js | 2 +- browser/base/content/sanitizeDialog.js | 8 ++++---- browser/base/content/social-content.js | 2 +- browser/base/content/sync/aboutSyncTabs.js | 2 +- browser/base/content/sync/addDevice.js | 6 +++--- browser/base/content/sync/genericChange.js | 4 ++-- browser/base/content/sync/setup.js | 8 ++++---- .../test/general/browser_aboutTabCrashed.js | 2 +- .../test/general/browser_alltabslistener.js | 2 +- .../content/test/general/browser_bug356571.js | 4 ++-- .../content/test/general/browser_bug567306.js | 2 +- .../test/general/browser_overflowScroll.js | 20 +++++++++---------- .../test/general/browser_permissions.js | 2 +- .../test/general/browser_sanitizeDialog.js | 10 +++++----- .../test/general/browser_trackingUI_1.js | 2 +- .../test/general/browser_trackingUI_2.js | 2 +- .../test/general/browser_trackingUI_4.js | 2 +- .../general/browser_trackingUI_telemetry.js | 2 +- .../test/general/content_aboutAccounts.js | 2 +- .../content/test/plugins/blocklist_proxy.js | 8 ++++---- .../content/test/plugins/browser_bug797677.js | 4 ++-- browser/base/content/webrtcIndicator.js | 2 +- .../tests/unit/head_dirprovider.js | 4 ++-- browser/components/distribution.js | 8 ++++---- .../components/downloads/test/unit/head.js | 8 ++++---- .../extensions/ext-browserAction.js | 2 +- .../components/extensions/ext-contextMenus.js | 12 +++++------ .../extensions/test/browser/head.js | 2 +- .../components/feeds/test/unit/head_feeds.js | 6 +++--- .../components/feeds/test/unit/test_355473.js | 2 +- browser/components/loop/test/xpcshell/head.js | 2 +- .../components/migration/IEProfileMigrator.js | 2 +- .../components/migration/content/migration.js | 6 +++--- .../migration/tests/unit/head_migration.js | 2 +- .../places/tests/unit/head_bookmarks.js | 8 ++++---- browser/components/preferences/blocklists.js | 2 +- .../preferences/in-content/preferences.js | 8 ++++---- browser/components/preferences/translation.js | 2 +- .../content/aboutPrivateBrowsing.js | 2 +- .../content/aboutSessionRestore.js | 2 +- .../components/shell/test/unit/test_421977.js | 6 +++--- browser/components/tabview/tabview.js | 8 ++++---- browser/components/uitour/test/browser_fxa.js | 2 +- .../uitour/test/browser_openPreferences.js | 2 +- .../test/browser_showMenu_controlCenter.js | 2 +- .../uitour/test/browser_trackingProtection.js | 2 +- browser/experiments/test/xpcshell/head.js | 2 +- browser/modules/Chat.jsm | 2 +- browser/modules/Sanitizer.jsm | 2 +- browser/modules/test/unit/social/head.js | 2 +- .../xpcshell/test_DirectoryLinksProvider.js | 2 +- caps/tests/unit/test_origin.js | 6 +++--- chrome/test/unit/head_crtestutils.js | 6 +++--- .../client/aboutdebugging/aboutdebugging.js | 2 +- .../animation-controller.js | 2 +- .../client/animationinspector/test/head.js | 2 +- .../test/unit/test_findOptimalTimeInterval.js | 2 +- .../test/unit/test_timeScale.js | 2 +- .../app-manager/content/connection-footer.js | 4 ++-- devtools/client/app-manager/content/device.js | 2 +- devtools/client/app-manager/content/index.js | 2 +- .../client/app-manager/content/projects.js | 8 ++++---- devtools/client/app-manager/test/head.js | 2 +- .../client/canvasdebugger/canvasdebugger.js | 2 +- devtools/client/canvasdebugger/test/head.js | 2 +- .../client/debugger/debugger-controller.js | 2 +- .../browser_dbg_addon4/bootstrap.js | 2 +- .../browser_dbg_addon5/bootstrap.js | 2 +- .../test/mochitest/code_frame-script.js | 2 +- .../client/debugger/test/mochitest/head.js | 2 +- .../client/fontinspector/font-inspector.js | 2 +- devtools/client/framework/connect/connect.js | 2 +- devtools/client/framework/test/shared-head.js | 2 +- .../framework/toolbox-process-window.js | 2 +- devtools/client/inspector/test/head.js | 8 ++++---- devtools/client/layoutview/test/head.js | 2 +- devtools/client/layoutview/view.js | 2 +- .../markupview/test/frame-script-utils.js | 2 +- devtools/client/markupview/test/head.js | 2 +- devtools/client/memory/initializer.js | 4 ++-- devtools/client/memory/test/mochitest/head.js | 10 +++++----- .../test/unit/test_action-take-snapshot.js | 2 +- .../netmonitor/netmonitor-controller.js | 2 +- devtools/client/netmonitor/test/head.js | 2 +- .../performance/performance-controller.js | 2 +- .../test/browser_perf-private-browsing.js | 2 +- devtools/client/performance/test/head.js | 2 +- devtools/client/performance/test/unit/head.js | 2 +- .../chrome/content/projecteditor-loader.js | 2 +- devtools/client/projecteditor/test/head.js | 2 +- .../promisedebugger/promise-controller.js | 2 +- .../responsivedesign-child.js | 2 +- devtools/client/scratchpad/scratchpad.js | 6 +++--- devtools/client/shadereditor/shadereditor.js | 2 +- devtools/client/shadereditor/test/head.js | 2 +- devtools/client/shared/browser-loader.js | 2 +- devtools/client/shared/frame-script-utils.js | 2 +- .../test/browser_layoutHelpers-getBoxQuads.js | 4 ++-- .../shared/test/browser_layoutHelpers.js | 2 +- devtools/client/shared/test/test-actor.js | 2 +- ...iablesView_filtering-without-controller.js | 6 +++--- .../test_VariablesView_getString_promise.js | 2 +- .../shared/test/unit/test_advanceValidate.js | 4 ++-- .../test/unit/test_attribute-parsing-01.js | 2 +- .../test/unit/test_attribute-parsing-02.js | 2 +- .../shared/test/unit/test_bezierCanvas.js | 2 +- .../shared/test/unit/test_cubicBezier.js | 2 +- .../client/shared/test/unit/test_undoStack.js | 2 +- .../test/browser_styleeditor_filesave.js | 4 ++-- .../browser_styleeditor_sourcemap_watching.js | 4 ++-- devtools/client/styleinspector/test/head.js | 2 +- .../test/unit/test_escapeCSSComment.js | 2 +- .../test/unit/test_parseDeclarations.js | 2 +- .../test_parsePseudoClassesAndAttributes.js | 2 +- .../test/unit/test_parseSingleValue.js | 2 +- .../test/unit/test_rewriteDeclarations.js | 2 +- devtools/client/webaudioeditor/includes.js | 2 +- devtools/client/webaudioeditor/test/head.js | 2 +- ...wser_webconsole_netlogging_reset_filter.js | 4 ++-- devtools/client/webide/content/addons.js | 2 +- devtools/client/webide/content/details.js | 2 +- .../webide/content/devicepreferences.js | 2 +- .../client/webide/content/devicesettings.js | 2 +- devtools/client/webide/content/logs.js | 2 +- devtools/client/webide/content/monitor.js | 2 +- devtools/client/webide/content/newapp.js | 6 +++--- .../client/webide/content/permissionstable.js | 2 +- devtools/client/webide/content/prefs.js | 2 +- .../client/webide/content/project-listing.js | 2 +- .../client/webide/content/runtime-listing.js | 2 +- .../client/webide/content/runtimedetails.js | 2 +- devtools/client/webide/content/simulator.js | 2 +- devtools/client/webide/content/webide.js | 6 +++--- devtools/client/webide/content/wifi-auth.js | 2 +- devtools/client/webide/test/head.js | 2 +- devtools/server/actors/highlighters.js | 8 ++++---- .../actors/highlighters/css-transform.js | 2 +- .../actors/highlighters/geometry-editor.js | 2 +- .../actors/highlighters/utils/markup.js | 2 +- devtools/server/actors/memprof.js | 6 +++--- devtools/server/tests/browser/head.js | 6 +++--- .../server/tests/mochitest/memprof-helpers.js | 18 ++++++++--------- devtools/server/tests/unit/head_dbg.js | 10 +++++----- .../shared/acorn/tests/unit/head_acorn.js | 2 +- .../apps/tests/debugger-protocol-helper.js | 6 +++--- devtools/shared/apps/tests/unit/head_apps.js | 10 +++++----- .../discovery/tests/unit/test_discovery.js | 2 +- .../tests/unit/head_heapsnapshot.js | 10 +++++----- .../jsbeautify/tests/unit/head_jsbeautify.js | 8 ++++---- devtools/shared/performance/test/head.js | 2 +- .../tests/unit/head_pretty-fast.js | 8 ++++---- .../shared/qrcode/tests/unit/test_encode.js | 2 +- .../shared/security/tests/unit/head_dbg.js | 10 +++++----- .../shared/tests/unit/test_indentation.js | 2 +- devtools/shared/shims/dbg-client.jsm | 2 +- .../sourcemap/tests/unit/head_sourcemap.js | 8 ++++---- devtools/shared/tern/tests/unit/head_tern.js | 2 +- devtools/shared/tests/unit/head_devtools.js | 8 ++++---- .../shared/transport/tests/unit/head_dbg.js | 10 +++++----- devtools/shared/webconsole/test/common.js | 2 +- .../test/unit/test_network_helper.js | 2 +- .../unit/test_security-info-certificate.js | 2 +- .../test/unit/test_security-info-parser.js | 2 +- .../test_security-info-protocol-version.js | 2 +- .../test/unit/test_security-info-state.js | 2 +- .../unit/test_security-info-static-hpkp.js | 2 +- .../test_security-info-weakness-reasons.js | 2 +- docshell/test/browser/browser_loadURI.js | 4 ++-- docshell/test/browser/frame-head.js | 2 +- docshell/test/unit/head_docshell.js | 6 +++--- .../unit/test_nsDefaultURIFixup_search.js | 14 ++++++------- .../test/unit_ipc/test_pb_notification_ipc.js | 4 ++-- dom/activities/tests/mochi/common.js | 2 +- .../test/system_message_chrome_script.js | 2 +- dom/apps/tests/chromeAddCert.js | 6 +++--- dom/apps/tests/test_operator_app_install.js | 6 +++--- dom/apps/tests/unit/head.js | 2 +- dom/base/test/browser_state_notifications.js | 2 +- dom/base/test/bug403852_fileOpener.js | 2 +- dom/base/test/chrome/cpows_child.js | 2 +- dom/base/test/chrome/test_domparsing.xul | 4 ++-- .../chrome/test_fileconstructor_tempfile.xul | 6 +++--- dom/base/test/file_simplecontentpolicy.js | 6 +++--- dom/base/test/fileapi_chromeScript.js | 2 +- dom/base/test/script_postmessages_fileList.js | 2 +- dom/base/test/test_copypaste.xul | 2 +- dom/base/test/unit/test_xhr_document.js | 6 +++--- dom/contacts/tests/test_migration_chrome.js | 2 +- .../tests/shim_app_as_test_chrome.js | 8 ++++---- dom/html/test/formSubmission_chrome.js | 2 +- dom/html/test/simpleFileOpener.js | 2 +- dom/indexedDB/test/chromeHelpers.js | 2 +- dom/indexedDB/test/extensions/bootstrap.js | 4 ++-- .../test/unit/xpcshell-head-parent-process.js | 2 +- .../test/xpcshell/test_inputport_data.js | 2 +- .../test/system_message_chrome_script.js | 2 +- .../tests/xpcshell/header_helpers.js | 2 +- .../tests/unit_stats/test_networkstats_db.js | 2 +- .../unit_stats/test_networkstats_service.js | 2 +- .../test_networkstats_service_proxy.js | 2 +- dom/newapps/test/xpcshell/test_install.js | 2 +- .../test/unit/common_test_notificationdb.js | 2 +- dom/payment/tests/unit/header_helper.js | 2 +- dom/permission/tests/unit/test_bug808734.js | 2 +- .../test/mochitest/browser_bug1196539.js | 2 +- .../test/mochitest/browser_pluginscroll.js | 6 +++--- .../browser_tabswitchbetweenplugins.js | 2 +- dom/plugins/test/mochitest/hang_test.js | 4 ++-- .../test/mochitest/test_hang_submit.xul | 4 ++-- .../test_privatemode_perwindowpb.xul | 4 ++-- dom/plugins/test/unit/head_plugins.js | 2 +- .../tests/unit/test_monitor_uncaught.js | 2 +- .../tests/system_message_chrome_script.js | 2 +- dom/security/test/unit/test_csp_reports.js | 8 ++++---- dom/settings/tests/test_settings_service.js | 6 +++--- .../tests/test_settings_service_callback.js | 6 +++--- .../test_settingsrequestmanager_messages.js | 2 +- dom/system/gonk/tests/header_helpers.js | 2 +- dom/system/gonk/tests/marionette/head.js | 2 +- .../gonk/tests/test_ril_system_messenger.js | 2 +- dom/telephony/test/marionette/head.js | 4 ++-- .../chrome/test_MozDomFullscreen_event.xul | 4 ++-- .../mochitest/chrome/test_geolocation.xul | 4 ++-- dom/tests/mochitest/webapps/head.js | 2 +- .../test_geolocation_position_unavailable.js | 8 ++++---- ...t_geolocation_position_unavailable_wrap.js | 6 +++--- dom/tests/unit/test_geolocation_provider.js | 8 ++++---- .../unit/test_geolocation_provider_timeout.js | 6 +++--- .../unit/test_geolocation_reset_accuracy.js | 4 ++-- .../test_geolocation_reset_accuracy_wrap.js | 4 ++-- dom/tests/unit/test_geolocation_timeout.js | 8 ++++---- .../unit/test_geolocation_timeout_wrap.js | 6 +++--- dom/wappush/gonk/WapPushManager.js | 2 +- dom/wappush/tests/header_helpers.js | 2 +- dom/workers/test/dom_worker_helper.js | 2 +- .../test/extensions/bootstrap/bootstrap.js | 4 ++-- embedding/test/browser_bug1204626.js | 4 ++-- .../tests/unit/test_wwauthpromptfactory.js | 4 ++-- extensions/cookie/test/unit/cookieprompt.js | 2 +- extensions/cookie/test/unit/head_cookies.js | 6 +++--- extensions/cookie/test/unit_ipc/test_child.js | 6 +++--- .../cookie/test/unit_ipc/test_parent.js | 6 +++--- .../hunspell/tests/unit/test_hunspell.js | 4 ++-- .../tests/mochitest/helper_bug1170484.js | 4 ++-- .../tests/CharsetDetectionTests.js | 4 ++-- image/test/unit/async_load_tests.js | 8 ++++---- image/test/unit/test_encoder_apng.js | 4 ++-- image/test/unit/test_encoder_png.js | 4 ++-- image/test/unit/test_imgtools.js | 4 ++-- image/test/unit/test_moz_icon_uri.js | 4 ++-- image/test/unit/test_private_channel.js | 8 ++++---- intl/locale/tests/unit/test_bug22310.js | 4 ++-- intl/locale/tests/unit/test_bug371611.js | 6 +++--- .../tests/unit/test_collation_mac_icu.js | 2 +- .../tests/unit/CharsetConversionTests.js | 6 +++--- intl/uconv/tests/unit/test_bug317216.js | 4 ++-- intl/uconv/tests/unit/test_bug340714.js | 4 ++-- intl/uconv/tests/unit/test_bug563618.js | 4 ++-- .../tests/unit/test_charset_conversion.js | 4 ++-- intl/uconv/tests/unit/test_utf8_illegals.js | 6 +++--- ipc/testshell/tests/test_ipcshell_child.js | 4 ++-- js/xpconnect/tests/chrome/test_bug793433.xul | 4 ++-- .../tests/chrome/test_chrometoSource.xul | 6 +++--- js/xpconnect/tests/chrome/test_cows.xul | 4 ++-- layout/tools/recording/recording.js | 2 +- layout/tools/reftest/reftest-content.js | 2 +- layout/tools/reftest/reftest.js | 2 +- memory/replace/dmd/test/test_dmd.js | 2 +- .../b2gdroid/components/MessagesBridge.jsm | 2 +- .../chrome/content/WebcompatReporter.js | 2 +- .../android/chrome/content/aboutAccounts.js | 6 +++--- mobile/android/chrome/content/aboutDevices.js | 2 +- .../android/chrome/content/aboutDownloads.js | 2 +- .../chrome/content/aboutHealthReport.js | 2 +- .../chrome/content/aboutPrivateBrowsing.js | 4 ++-- mobile/android/chrome/content/config.js | 2 +- .../android/components/ImageBlockingPolicy.js | 2 +- .../android/modules/FxAccountsWebChannel.jsm | 2 +- .../roboextender/base/SelectionUtils.js | 2 +- .../browser/robocop/testBrowserDiscovery.js | 2 +- .../tests/browser/robocop/testFindInPage.js | 2 +- .../browser/robocop/testHistoryService.js | 2 +- .../browser/robocop/testReadingListCache.js | 2 +- .../browser/robocop/testSelectionCarets.js | 2 +- .../browser/robocop/testTrackingProtection.js | 2 +- .../tests/browser/robocop/testUITelemetry.js | 6 +++--- .../browser/robocop/testVideoControls.js | 2 +- modules/libjar/test/unit/test_bug278262.js | 4 ++-- modules/libjar/test/unit/test_bug336691.js | 4 ++-- modules/libjar/test/unit/test_bug370103.js | 6 +++--- modules/libjar/test/unit/test_bug379841.js | 4 ++-- modules/libjar/test/unit/test_bug407303.js | 6 +++--- modules/libjar/test/unit/test_bug589292.js | 6 +++--- modules/libjar/test/unit/test_bug597702.js | 6 +++--- modules/libjar/test/unit/test_bug637286.js | 6 +++--- modules/libjar/test/unit/test_bug658093.js | 6 +++--- modules/libjar/test/unit/test_not_found.js | 6 +++--- modules/libjar/test/unit/test_umlaute.js | 4 ++-- modules/libjar/test/unit/test_uncompressed.js | 4 ++-- .../zipwriter/test/unit/head_zipwriter.js | 4 ++-- .../zipwriter/test/unit/test_asyncadd.js | 2 +- modules/libmar/tests/unit/head_libmar.js | 4 ++-- modules/libpref/test/unit/head_libPrefs.js | 8 ++++---- .../test/unit_ipc/test_existing_prefs.js | 4 ++-- .../test/unit_ipc/test_initial_prefs.js | 4 ++-- .../test/unit_ipc/test_observed_prefs.js | 4 ++-- .../test/unit_ipc/test_update_prefs.js | 4 ++-- .../test/unit_ipc/test_user_default_prefs.js | 4 ++-- netwerk/cookie/test/unit/test_bug1155169.js | 2 +- netwerk/cookie/test/unit/test_bug643051.js | 4 ++-- netwerk/cookie/test/unit/test_parser_0001.js | 4 ++-- netwerk/cookie/test/unit/test_parser_0019.js | 4 ++-- .../test/unit_ipc/test_ipc_parser_0001.js | 2 +- .../test/unit_ipc/test_ipc_parser_0019.js | 2 +- netwerk/protocol/http/PackagedAppUtils.js | 2 +- netwerk/test/unit/client_cert_chooser.js | 2 +- netwerk/test/unit/head_cache2.js | 8 ++++---- netwerk/test/unit/socks_client_subprocess.js | 6 +++--- netwerk/test/unit/test_addr_in_use_error.js | 2 +- netwerk/test/unit/test_bug470716.js | 2 +- .../unit/test_file_partial_inputstream.js | 2 +- netwerk/test/unit/test_invalidport.js | 2 +- netwerk/test/unit/test_net_addr.js | 2 +- .../test/unit/test_packaged_app_service.js | 4 ++-- netwerk/test/unit/test_packaged_app_utils.js | 2 +- netwerk/test/unit/test_socks.js | 2 +- netwerk/test/unit/test_speculative_connect.js | 2 +- .../test_suspend_channel_before_connect.js | 2 +- netwerk/test/unit/test_udp_multicast.js | 2 +- netwerk/test/unit/test_unix_domain.js | 2 +- netwerk/test/unit_ipc/head_cc.js | 8 ++++---- rdf/tests/unit/test_rdfredirect.js | 8 ++++---- security/manager/ssl/tests/unit/head_psm.js | 2 +- security/manager/tools/genHPKPStaticPins.js | 2 +- .../tools/genIntolerantFallbackList.js | 2 +- security/manager/tools/genRootCAHashes.js | 8 ++++---- security/manager/tools/getHSTSPreloadList.js | 8 ++++---- security/manager/tools/makeCNNICHashes.js | 6 +++--- services/cloudsync/tests/xpcshell/head.js | 2 +- services/common/async.js | 2 +- services/common/bagheeraclient.js | 2 +- services/common/hawkclient.js | 2 +- services/common/hawkrequest.js | 2 +- services/common/logmanager.js | 2 +- .../common/modules-testing/bagheeraserver.js | 2 +- services/common/modules-testing/logging.js | 2 +- .../common/modules-testing/storageserver.js | 2 +- services/common/observers.js | 8 ++++---- services/common/rest.js | 2 +- services/common/stringbundle.js | 2 +- services/common/tests/unit/head_global.js | 2 +- services/common/tokenserverclient.js | 2 +- services/common/utils.js | 2 +- .../crypto/component/tests/unit/test_jpake.js | 4 ++-- services/crypto/modules/WeaveCrypto.js | 6 +++--- services/crypto/modules/utils.js | 2 +- services/crypto/tests/unit/head_helpers.js | 8 ++++---- .../tests/xpcshell/test_policy.js | 2 +- services/fxaccounts/FxAccountsCommon.js | 2 +- services/fxaccounts/tests/xpcshell/head.js | 2 +- .../fxaccounts/tests/xpcshell/test_manager.js | 2 +- .../tests/xpcshell/test_healthreporter.js | 2 +- .../tests/xpcshell/test_profile.js | 2 +- .../tests/xpcshell/test_provider_addons.js | 2 +- .../tests/xpcshell/test_provider_appinfo.js | 2 +- .../tests/xpcshell/test_provider_crashes.js | 2 +- .../tests/xpcshell/test_provider_hotfix.js | 2 +- .../tests/xpcshell/test_provider_places.js | 2 +- .../tests/xpcshell/test_provider_searches.js | 2 +- .../tests/xpcshell/test_provider_sessions.js | 2 +- .../tests/xpcshell/test_provider_sysinfo.js | 2 +- .../tests/xpcshell/test_metrics_provider.js | 2 +- .../xpcshell/test_metrics_provider_manager.js | 2 +- .../tests/xpcshell/test_metrics_storage.js | 2 +- services/mobileid/tests/xpcshell/head.js | 4 ++-- services/sync/modules-testing/fakeservices.js | 2 +- services/sync/modules-testing/fxa_utils.js | 2 +- services/sync/modules-testing/rotaryengine.js | 2 +- services/sync/modules-testing/utils.js | 2 +- services/sync/modules/addonsreconciler.js | 2 +- services/sync/modules/addonutils.js | 2 +- services/sync/modules/browserid_identity.js | 2 +- services/sync/modules/engines.js | 2 +- services/sync/modules/engines/addons.js | 2 +- services/sync/modules/engines/bookmarks.js | 6 +++--- services/sync/modules/engines/clients.js | 2 +- services/sync/modules/engines/forms.js | 6 +++--- services/sync/modules/engines/history.js | 8 ++++---- services/sync/modules/engines/passwords.js | 2 +- services/sync/modules/engines/prefs.js | 6 +++--- services/sync/modules/engines/tabs.js | 2 +- services/sync/modules/identity.js | 2 +- services/sync/modules/jpakeclient.js | 2 +- services/sync/modules/keys.js | 2 +- services/sync/modules/notifications.js | 8 ++++---- services/sync/modules/policies.js | 2 +- services/sync/modules/record.js | 8 ++++---- services/sync/modules/resource.js | 8 ++++---- services/sync/modules/rest.js | 2 +- services/sync/modules/service.js | 8 ++++---- services/sync/modules/stages/cluster.js | 2 +- services/sync/modules/stages/declined.js | 2 +- services/sync/modules/stages/enginesync.js | 2 +- services/sync/modules/status.js | 8 ++++---- services/sync/modules/userapi.js | 2 +- services/sync/modules/util.js | 2 +- services/sync/tests/unit/head_appinfo.js | 2 +- services/sync/tests/unit/head_http_server.js | 2 +- .../mozmill/resource/driver/controller.js | 6 +++--- .../mozmill/resource/driver/elementslib.js | 6 +++--- .../mozmill/resource/driver/mozelement.js | 6 +++--- .../mozmill/resource/driver/mozmill.js | 6 +++--- .../mozmill/resource/modules/assertions.js | 2 +- .../mozmill/resource/modules/frame.js | 6 +++--- .../mozmill/resource/modules/windows.js | 6 +++--- .../mozmill/resource/stdlib/EventUtils.js | 4 ++-- .../extensions/mozmill/resource/stdlib/os.js | 6 +++--- .../mozmill/resource/stdlib/utils.js | 6 +++--- .../marionette/atoms/b2g_update_test.js | 2 +- testing/marionette/command.js | 2 +- testing/marionette/dispatcher.js | 2 +- testing/marionette/driver.js | 2 +- testing/marionette/emulator.js | 2 +- testing/marionette/error.js | 2 +- testing/marionette/modal.js | 2 +- testing/marionette/proxy.js | 2 +- testing/marionette/server.js | 2 +- .../BrowserTestUtils/content/content-task.js | 2 +- .../BrowserTestUtils/content/content-utils.js | 2 +- .../tests/xpcshell/test_mockRegistrar.js | 2 +- .../talos/pageloader/chrome/talos-content.js | 2 +- .../chrome/talos-powers-content.js | 2 +- .../talos/talos/tests/tabswitch/bootstrap.js | 2 +- .../xpcshell/example/unit/check_profile.js | 2 +- .../example/unit/test_do_get_tempdir.js | 2 +- .../aboutmemory/content/aboutMemory.js | 8 ++++---- .../content/aboutPerformance.js | 10 +++++----- .../aboutperformance/tests/browser/head.js | 2 +- .../alerts/resources/content/alert.js | 2 +- .../tests/unit/head_autocomplete.js | 4 ++-- .../captivedetect/test/unit/head_setprefs.js | 2 +- .../tests/unit/head_contentPrefs.js | 8 ++++---- .../contentprefs/tests/unit_cps2/head.js | 2 +- .../tests/xpcshell/test_crash_manager.js | 2 +- .../tests/xpcshell/test_crash_service.js | 2 +- .../tests/xpcshell/test_crash_store.js | 2 +- .../test/schema_migration/head_migration.js | 6 +++--- .../test/unit/head_download_manager.js | 8 ++++---- .../test/unit/test_privatebrowsing_cancel.js | 2 +- toolkit/components/extensions/ext-alarms.js | 2 +- .../extensions/ext-backgroundPage.js | 2 +- .../extensions/ext-notifications.js | 2 +- toolkit/components/extensions/ext-runtime.js | 2 +- toolkit/components/extensions/ext-storage.js | 2 +- .../extensions/ext-webNavigation.js | 2 +- .../components/extensions/ext-webRequest.js | 2 +- .../content/requestAutocomplete.js | 2 +- .../formautofill/test/chrome/loader.js | 2 +- .../formautofill/test/chrome/loader_parent.js | 2 +- .../formautofill/test/xpcshell/loader.js | 2 +- .../components/gfx/content/gfxFrameScript.js | 2 +- .../jsdownloads/test/browser/head.js | 8 ++++---- .../components/jsdownloads/test/unit/head.js | 8 ++++---- .../test/unit/test_mediasniffer.js | 4 ++-- .../test/unit/test_mediasniffer_ext.js | 8 ++++---- .../content/passwordManagerCommon.js | 2 +- .../browser/browser_passwordmgr_switchtab.js | 2 +- .../components/passwordmgr/test/unit/head.js | 2 +- .../PerformanceStats-content.js | 2 +- .../perfmonitoring/tests/browser/head.js | 2 +- toolkit/components/places/PlacesUtils.jsm | 2 +- .../tests/autocomplete/head_autocomplete.js | 8 ++++---- .../places/tests/bookmarks/head_bookmarks.js | 8 ++++---- .../places/tests/chrome/test_303567.xul | 6 +++--- .../places/tests/chrome/test_341972a.xul | 6 +++--- .../places/tests/chrome/test_341972b.xul | 6 +++--- .../places/tests/chrome/test_342484.xul | 6 +++--- .../places/tests/chrome/test_371798.xul | 2 +- .../places/tests/chrome/test_381357.xul | 6 +++--- .../tests/chrome/test_favicon_annotations.xul | 6 +++--- .../tests/chrome/test_reloadLivemarks.xul | 6 +++--- .../tests/expiration/head_expiration.js | 8 ++++---- .../places/tests/favicons/head_favicons.js | 8 ++++---- .../places/tests/history/head_history.js | 8 ++++---- .../places/tests/inline/head_autocomplete.js | 8 ++++---- .../places/tests/migration/head_migration.js | 2 +- .../tests/mochitest/bug_411966/redirect.js | 6 +++--- .../places/tests/network/head_network.js | 8 ++++---- .../places/tests/queries/head_queries.js | 8 ++++---- .../unifiedcomplete/head_autocomplete.js | 8 ++++---- .../places/tests/unit/head_bookmarks.js | 8 ++++---- .../prompts/content/commonDialog.js | 8 ++++---- .../prompts/content/selectDialog.js | 8 ++++---- .../components/satchel/test/parent_utils.js | 2 +- .../satchel/test/unit/head_satchel.js | 6 +++--- .../search/tests/xpcshell/head_search.js | 2 +- .../components/social/FrameWorkerContent.js | 2 +- .../components/social/test/xpcshell/head.js | 2 +- .../startup/tests/unit/test_startup_crash.js | 4 ++-- .../components/telemetry/tests/unit/head.js | 2 +- .../tests/xpcshell/test_terminator_record.js | 6 +++--- .../tests/xpcshell/test_terminator_reload.js | 6 +++--- .../content/backgroundPageThumbsContent.js | 2 +- .../url-classifier/content/listmanager.js | 2 +- .../tests/unit/head_urlclassifier.js | 8 ++++---- .../tests/unit/head_urlformatter.js | 6 +++--- .../viewsource/content/viewSource-content.js | 2 +- .../viewsource/content/viewSource.js | 2 +- .../tests/chrome/window_persistence.xul | 4 ++-- toolkit/content/aboutAbout.js | 4 ++-- toolkit/content/aboutNetworking.js | 6 +++--- toolkit/content/aboutServiceWorkers.js | 2 +- toolkit/content/aboutSupport.js | 2 +- toolkit/content/aboutTelemetry.js | 6 +++--- toolkit/content/aboutwebrtc/aboutWebrtc.js | 2 +- .../tests/browser/browser_bug982298.js | 2 +- .../tests/chrome/RegisterUnregisterChrome.js | 6 +++--- .../tests/unit/test_contentAreaUtils.js | 6 +++--- .../tests/widgets/test_popupreflows.xul | 2 +- toolkit/crashreporter/content/crashes.js | 2 +- .../test/unit/test_event_files.js | 2 +- .../identity/tests/chrome/test_sandbox.xul | 6 +++--- toolkit/identity/tests/unit/head_identity.js | 8 ++++---- .../modules/addons/WebNavigationContent.js | 2 +- toolkit/modules/addons/WebRequestContent.js | 8 ++++---- .../tests/browser/browser_Deprecated.js | 4 ++-- .../modules/tests/browser/browser_Finder.js | 2 +- .../browser/browser_RemoteWebNavigation.js | 2 +- .../tests/browser/browser_WebNavigation.js | 2 +- .../tests/browser/browser_WebRequest.js | 2 +- .../browser/browser_WebRequest_cookies.js | 2 +- .../browser/browser_WebRequest_filtering.js | 2 +- .../tests/chrome/test_bug544442_checkCert.xul | 6 +++--- .../tests/xpcshell/test_DeferredTask.js | 2 +- .../tests/xpcshell/test_GMPInstallManager.js | 4 ++-- toolkit/modules/tests/xpcshell/test_Log.js | 2 +- .../tests/xpcshell/test_NewTabUtils.js | 2 +- .../tests/xpcshell/test_Preferences.js | 2 +- .../modules/tests/xpcshell/test_Services.js | 8 ++++---- .../xpcshell/test_TelemetryTimestamps.js | 6 +++--- .../test_UpdateUtils_updatechannel.js | 2 +- .../tests/xpcshell/test_UpdateUtils_url.js | 2 +- .../modules/tests/xpcshell/test_client_id.js | 2 +- .../tests/xpcshell/test_session_recorder.js | 2 +- toolkit/modules/tests/xpcshell/test_sqlite.js | 2 +- .../tests/xpcshell/test_sqlite_shutdown.js | 2 +- toolkit/modules/tests/xpcshell/test_task.js | 8 ++++---- .../tests/xpcshell/test_web_channel.js | 2 +- .../tests/xpcshell/test_web_channel_broker.js | 2 +- .../test_taskbarprogress_downloadstates.xul | 2 +- .../mozapps/downloads/tests/chrome/utils.js | 6 +++--- .../tests/unit/test_DownloadPaths.js | 8 ++++---- .../mozapps/extensions/content/extensions.js | 8 ++++---- .../mozapps/extensions/content/newaddon.js | 6 +++--- .../extensions/content/selectAddons.js | 4 ++-- .../mozapps/extensions/internal/Content.js | 2 +- .../internal/ProductAddonChecker.jsm | 6 +++--- .../extensions/internal/XPIProviderUtils.js | 8 ++++---- .../browser_plugin_enabled_state_locked.js | 2 +- .../extensions/test/xpcshell/head_addons.js | 8 ++++---- .../xpcshell/test_LightweightThemeManager.js | 4 ++-- .../test/xpcshell/test_ProductAddonChecker.js | 4 ++-- .../test_blocklist_metadata_filters.js | 2 +- .../test/xpcshell/test_blocklist_prefs.js | 2 +- .../test/xpcshell/test_blocklist_regexp.js | 2 +- .../test/xpcshell/test_blocklistchange.js | 8 ++++---- .../test/xpcshell/test_bug335238.js | 4 ++-- .../test/xpcshell/test_bug393285.js | 2 +- .../test/xpcshell/test_bug406118.js | 2 +- .../test/xpcshell/test_bug449027.js | 4 ++-- .../test/xpcshell/test_bug455906.js | 8 ++++---- .../test/xpcshell/test_bug514327_1.js | 4 ++-- .../test/xpcshell/test_bug514327_2.js | 4 ++-- .../test/xpcshell/test_bug514327_3.js | 8 ++++---- .../test/xpcshell/test_bug542391.js | 8 ++++---- .../test/xpcshell/test_bug594058.js | 2 +- .../test/xpcshell/test_bug619730.js | 6 +++--- .../test/xpcshell/test_duplicateplugins.js | 2 +- .../test/xpcshell/test_gfxBlacklist_Device.js | 2 +- .../xpcshell/test_gfxBlacklist_DriverNew.js | 2 +- .../test_gfxBlacklist_Equal_DriverNew.js | 2 +- .../test_gfxBlacklist_Equal_DriverOld.js | 2 +- .../xpcshell/test_gfxBlacklist_Equal_OK.js | 2 +- .../test_gfxBlacklist_GTE_DriverOld.js | 2 +- .../test/xpcshell/test_gfxBlacklist_GTE_OK.js | 2 +- .../test_gfxBlacklist_No_Comparison.js | 2 +- .../test/xpcshell/test_gfxBlacklist_OK.js | 2 +- .../test/xpcshell/test_gfxBlacklist_OS.js | 2 +- .../test_gfxBlacklist_OSVersion_match.js | 2 +- ...cklist_OSVersion_mismatch_DriverVersion.js | 2 +- ...xBlacklist_OSVersion_mismatch_OSVersion.js | 2 +- .../test/xpcshell/test_gfxBlacklist_Vendor.js | 2 +- .../xpcshell/test_gfxBlacklist_Version.js | 2 +- .../test/xpcshell/test_gmpProvider.js | 2 +- .../extensions/test/xpcshell/test_install.js | 6 +++--- .../xpcshell/test_install_strictcompat.js | 6 +++--- .../test/xpcshell/test_metadata_update.js | 8 ++++---- .../test/xpcshell/test_pluginInfoURL.js | 2 +- .../test/xpcshell/test_system_reset.js | 2 +- .../test/xpcshell/test_system_update.js | 6 +++--- toolkit/mozapps/handling/content/dialog.js | 6 +++--- toolkit/mozapps/installer/precompile_cache.js | 6 +++--- toolkit/webapps/tests/head.js | 2 +- .../tests/unit/head_handlerService.js | 8 ++++---- .../tests/unit_ipc/test_encoding.js | 8 ++++---- webapprt/content/downloads/downloads.js | 2 +- webapprt/content/mochitest.js | 4 ++-- webapprt/content/webapp.js | 6 +++--- widget/tests/test_bug760802.xul | 4 ++-- widget/tests/test_panel_mouse_coords.xul | 4 ++-- .../tests/unit/test_taskbar_jumplistitems.js | 4 ++-- xpcom/tests/unit/test_bug121341.js | 4 ++-- xpcom/tests/unit/test_bug325418.js | 4 ++-- xpcom/tests/unit/test_bug364285-1.js | 4 ++-- xpcom/tests/unit/test_bug374754.js | 4 ++-- xpcom/tests/unit/test_bug476919.js | 4 ++-- xpcom/tests/unit/test_bug656331.js | 4 ++-- xpcom/tests/unit/test_bug725015.js | 4 ++-- xpcom/tests/unit/test_comp_no_aslr.js | 4 ++-- xpcom/tests/unit/test_compmgr_warnings.js | 4 ++-- .../unit/test_debugger_malloc_size_of.js | 2 +- xpcom/tests/unit/test_file_createUnique.js | 6 +++--- xpcom/tests/unit/test_file_equality.js | 6 +++--- xpcom/tests/unit/test_file_renameTo.js | 4 ++-- xpcom/tests/unit/test_hidden_files.js | 4 ++-- xpcom/tests/unit/test_home.js | 4 ++-- xpcom/tests/unit/test_iniProcessor.js | 6 +++--- xpcom/tests/unit/test_ioutil.js | 6 +++--- xpcom/tests/unit/test_localfile.js | 6 +++--- xpcom/tests/unit/test_notxpcom_scriptable.js | 8 ++++---- xpcom/tests/unit/test_nsIMutableArray.js | 8 ++++---- xpcom/tests/unit/test_pipe.js | 8 ++++---- xpcom/tests/unit/test_process_directives.js | 4 ++-- xpcom/tests/unit/test_seek_multiplex.js | 8 ++++---- xpcom/tests/unit/test_storagestream.js | 6 +++--- xpcom/tests/unit/test_streams.js | 6 +++--- xpcom/tests/unit/test_stringstream.js | 6 +++--- xpcom/tests/unit/test_windows_shortcut.js | 10 +++++----- .../test/test_hiddenPrivateWindow.xul | 2 +- 665 files changed, 1243 insertions(+), 1243 deletions(-) diff --git a/accessible/tests/mochitest/jsat/dom_helper.js b/accessible/tests/mochitest/jsat/dom_helper.js index 3e8f06d26192..431bed1d55ba 100644 --- a/accessible/tests/mochitest/jsat/dom_helper.js +++ b/accessible/tests/mochitest/jsat/dom_helper.js @@ -4,8 +4,8 @@ SimpleTest, getBoundsForDOMElm, Point, Utils */ /* exported loadJSON, eventMap */ -var Ci = Components.interfaces; -var Cu = Components.utils; +const Ci = Components.interfaces; +const Cu = Components.utils; Cu.import('resource://gre/modules/accessibility/Utils.jsm'); Cu.import('resource://gre/modules/Geometry.jsm'); diff --git a/accessible/tests/mochitest/jsat/output.js b/accessible/tests/mochitest/jsat/output.js index 5afcc8a666d6..cd9b2a9f5fec 100644 --- a/accessible/tests/mochitest/jsat/output.js +++ b/accessible/tests/mochitest/jsat/output.js @@ -1,4 +1,4 @@ -var Cu = Components.utils; +const Cu = Components.utils; const PREF_UTTERANCE_ORDER = "accessibility.accessfu.utterance"; Cu.import('resource://gre/modules/accessibility/Utils.jsm'); diff --git a/addon-sdk/source/modules/system/Startup.js b/addon-sdk/source/modules/system/Startup.js index 62bdd619e522..f62c94aaf562 100644 --- a/addon-sdk/source/modules/system/Startup.js +++ b/addon-sdk/source/modules/system/Startup.js @@ -5,7 +5,7 @@ var EXPORTED_SYMBOLS = ["Startup"]; -var { utils: Cu, interfaces: Ci, classes: Cc } = Components; +const { utils: Cu, interfaces: Ci, classes: Cc } = Components; const { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); const { defer } = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise; diff --git a/addon-sdk/source/python-lib/cuddlefish/mobile-utils/bootstrap.js b/addon-sdk/source/python-lib/cuddlefish/mobile-utils/bootstrap.js index a0120b0be192..44e81b30dfa5 100644 --- a/addon-sdk/source/python-lib/cuddlefish/mobile-utils/bootstrap.js +++ b/addon-sdk/source/python-lib/cuddlefish/mobile-utils/bootstrap.js @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; -var Cu = Components.utils; +const Cu = Components.utils; Cu.import("resource://gre/modules/Services.jsm"); diff --git a/b2g/chrome/content/settings.js b/b2g/chrome/content/settings.js index 53830361723e..ab7074a47544 100644 --- a/b2g/chrome/content/settings.js +++ b/b2g/chrome/content/settings.js @@ -8,10 +8,10 @@ window.performance.mark('gecko-settings-loadstart'); -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; -var Cr = Components.results; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; // The load order is important here SettingsRequestManager _must_ be loaded // prior to using SettingsListener otherwise there is a race in acquiring the diff --git a/b2g/chrome/content/shell.js b/b2g/chrome/content/shell.js index 51d3b406c463..fcb8d83473e0 100644 --- a/b2g/chrome/content/shell.js +++ b/b2g/chrome/content/shell.js @@ -1502,7 +1502,7 @@ const saveWindowGeometry = () => { } window.addEventListener("unload", saveWindowGeometry); -var baseWindow = window.QueryInterface(Ci.nsIInterfaceRequestor) +let baseWindow = window.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIWebNavigation) .QueryInterface(Ci.nsIDocShellTreeItem) .treeOwner diff --git a/b2g/chrome/content/shell_remote.js b/b2g/chrome/content/shell_remote.js index 1c882550a7f1..0d34f2c8cca4 100644 --- a/b2g/chrome/content/shell_remote.js +++ b/b2g/chrome/content/shell_remote.js @@ -6,7 +6,7 @@ "use strict"; -var {utils: Cu} = Components; +const {utils: Cu} = Components; Cu.import("resource://gre/modules/Services.jsm"); @@ -14,7 +14,7 @@ function debug(aStr) { // dump(" -*- ShellRemote.js: " + aStr + "\n"); } -var remoteShell = { +let remoteShell = { get homeURL() { let systemAppManifestURL = Services.io.newURI(this.systemAppManifestURL, null, null); diff --git a/b2g/chrome/content/test/mochitest/RecordingStatusChromeScript.js b/b2g/chrome/content/test/mochitest/RecordingStatusChromeScript.js index 1a5ed82743b8..3d75d83dc17d 100644 --- a/b2g/chrome/content/test/mochitest/RecordingStatusChromeScript.js +++ b/b2g/chrome/content/test/mochitest/RecordingStatusChromeScript.js @@ -1,7 +1,7 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ -var { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components; +const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components; const { Services } = Cu.import('resource://gre/modules/Services.jsm'); const { SystemAppProxy } = Cu.import('resource://gre/modules/SystemAppProxy.jsm'); diff --git a/b2g/components/MultiscreenHandler.jsm b/b2g/components/MultiscreenHandler.jsm index e9b4058e8c57..3fa6826779cc 100644 --- a/b2g/components/MultiscreenHandler.jsm +++ b/b2g/components/MultiscreenHandler.jsm @@ -15,11 +15,11 @@ function debug(aStr) { // dump("MultiscreenHandler: " + aStr + "\n"); } -var window = Services.wm.getMostRecentWindow("navigator:browser"); +let window = Services.wm.getMostRecentWindow("navigator:browser"); // Multi-screen support on b2g. The following implementation will open a new // top-level window once we receive a display connected event. -var MultiscreenHandler = { +let MultiscreenHandler = { topLevelWindows: new Map(), diff --git a/b2g/components/test/mochitest/filepicker_path_handler_chrome.js b/b2g/components/test/mochitest/filepicker_path_handler_chrome.js index a175746cb93f..59fbdc590850 100644 --- a/b2g/components/test/mochitest/filepicker_path_handler_chrome.js +++ b/b2g/components/test/mochitest/filepicker_path_handler_chrome.js @@ -4,8 +4,8 @@ 'use strict'; -var Cc = Components.classes; -var Ci = Components.interfaces; +const Cc = Components.classes; +const Ci = Components.interfaces; // use ppmm to handle file-picker message. var ppmm = Cc['@mozilla.org/parentprocessmessagemanager;1'] diff --git a/b2g/components/test/mochitest/permission_handler_chrome.js b/b2g/components/test/mochitest/permission_handler_chrome.js index 9bf3e7819a4a..2e2f84bebaed 100644 --- a/b2g/components/test/mochitest/permission_handler_chrome.js +++ b/b2g/components/test/mochitest/permission_handler_chrome.js @@ -8,9 +8,9 @@ function debug(str) { dump("CHROME PERMISSON HANDLER -- " + str + "\n"); } -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; const { Services } = Cu.import("resource://gre/modules/Services.jsm"); const { SystemAppProxy } = Cu.import("resource://gre/modules/SystemAppProxy.jsm"); diff --git a/b2g/components/test/mochitest/presentation_prompt_handler_chrome.js b/b2g/components/test/mochitest/presentation_prompt_handler_chrome.js index 4407e58d287a..7180bd014e33 100644 --- a/b2g/components/test/mochitest/presentation_prompt_handler_chrome.js +++ b/b2g/components/test/mochitest/presentation_prompt_handler_chrome.js @@ -8,7 +8,7 @@ dump('presentation_prompt_handler_chrome: ' + str + '\n'); } -var { classes: Cc, interfaces: Ci, utils: Cu } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; const { XPCOMUtils } = Cu.import('resource://gre/modules/XPCOMUtils.jsm'); const { SystemAppProxy } = Cu.import('resource://gre/modules/SystemAppProxy.jsm'); diff --git a/b2g/components/test/mochitest/presentation_ui_glue_handler_chrome.js b/b2g/components/test/mochitest/presentation_ui_glue_handler_chrome.js index 3937f3f9593e..75c04e432971 100644 --- a/b2g/components/test/mochitest/presentation_ui_glue_handler_chrome.js +++ b/b2g/components/test/mochitest/presentation_ui_glue_handler_chrome.js @@ -4,7 +4,7 @@ 'use strict'; -var { classes: Cc, interfaces: Ci, utils: Cu } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; const { XPCOMUtils } = Cu.import('resource://gre/modules/XPCOMUtils.jsm'); const { SystemAppProxy } = Cu.import('resource://gre/modules/SystemAppProxy.jsm'); diff --git a/b2g/components/test/mochitest/screenshot_helper.js b/b2g/components/test/mochitest/screenshot_helper.js index 0320a14c16af..d2ae8b5dcfcd 100644 --- a/b2g/components/test/mochitest/screenshot_helper.js +++ b/b2g/components/test/mochitest/screenshot_helper.js @@ -1,5 +1,5 @@ -var Cu = Components.utils; -var Ci = Components.interfaces; +const Cu = Components.utils; +const Ci = Components.interfaces; Cu.importGlobalProperties(['File']); diff --git a/b2g/components/test/mochitest/systemapp_helper.js b/b2g/components/test/mochitest/systemapp_helper.js index 0f2bd4099f42..5a901b48416f 100644 --- a/b2g/components/test/mochitest/systemapp_helper.js +++ b/b2g/components/test/mochitest/systemapp_helper.js @@ -1,4 +1,4 @@ -var Cu = Components.utils; +const Cu = Components.utils; const { Services } = Cu.import("resource://gre/modules/Services.jsm"); diff --git a/b2g/components/test/unit/file_killswitch.js b/b2g/components/test/unit/file_killswitch.js index 0507e9ba7ae6..6ce8dd76c924 100644 --- a/b2g/components/test/unit/file_killswitch.js +++ b/b2g/components/test/unit/file_killswitch.js @@ -4,7 +4,7 @@ "use strict"; -var {classes: Cc, interfaces: Ci, utils: Cu} = Components; +const {classes: Cc, interfaces: Ci, utils: Cu} = Components; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/NetUtil.jsm"); diff --git a/b2g/components/test/unit/head_identity.js b/b2g/components/test/unit/head_identity.js index 604a7728486a..d42859025ae6 100644 --- a/b2g/components/test/unit/head_identity.js +++ b/b2g/components/test/unit/head_identity.js @@ -1,8 +1,8 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ -var Ci = Components.interfaces; -var Cu = Components.utils; +const Ci = Components.interfaces; +const Cu = Components.utils; // The following boilerplate makes sure that XPCOM calls // that use the profile directory work. diff --git a/b2g/components/test/unit/head_logshake_gonk.js b/b2g/components/test/unit/head_logshake_gonk.js index e94234f1f043..9985387efe26 100644 --- a/b2g/components/test/unit/head_logshake_gonk.js +++ b/b2g/components/test/unit/head_logshake_gonk.js @@ -14,9 +14,9 @@ "use strict"; -var Cu = Components.utils; -var Ci = Components.interfaces; -var Cc = Components.classes; +const Cu = Components.utils; +const Ci = Components.interfaces; +const Cc = Components.classes; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/osfile.jsm"); diff --git a/b2g/components/test/unit/test_aboutserviceworkers.js b/b2g/components/test/unit/test_aboutserviceworkers.js index d1a7d41aaad7..35c7c9f0b54e 100644 --- a/b2g/components/test/unit/test_aboutserviceworkers.js +++ b/b2g/components/test/unit/test_aboutserviceworkers.js @@ -3,7 +3,7 @@ "use strict"; -var {utils: Cu} = Components; +const {utils: Cu} = Components; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); diff --git a/b2g/components/test/unit/test_fxaccounts.js b/b2g/components/test/unit/test_fxaccounts.js index 1cc8a1c0a8c1..c84176a624cc 100644 --- a/b2g/components/test/unit/test_fxaccounts.js +++ b/b2g/components/test/unit/test_fxaccounts.js @@ -3,7 +3,7 @@ "use strict"; -var {utils: Cu} = Components; +const {utils: Cu} = Components; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); diff --git a/b2g/components/test/unit/test_killswitch.js b/b2g/components/test/unit/test_killswitch.js index c7d4a448de5b..395dccf4fc10 100644 --- a/b2g/components/test/unit/test_killswitch.js +++ b/b2g/components/test/unit/test_killswitch.js @@ -4,7 +4,7 @@ "use strict"; -var {results: Cr} = Components; +const {results: Cr} = Components; // Trivial test just to make sure we have no syntax error add_test(function test_ksm_ok() { diff --git a/b2g/components/test/unit/test_logparser.js b/b2g/components/test/unit/test_logparser.js index 624dcc6e286b..dfd16de456b5 100644 --- a/b2g/components/test/unit/test_logparser.js +++ b/b2g/components/test/unit/test_logparser.js @@ -1,6 +1,6 @@ /* jshint moz: true */ -var {utils: Cu, classes: Cc, interfaces: Ci} = Components; +const {utils: Cu, classes: Cc, interfaces: Ci} = Components; function debug(msg) { var timestamp = Date.now(); diff --git a/b2g/components/test/unit/test_logshake.js b/b2g/components/test/unit/test_logshake.js index cfb81b8933c8..2c28d4d28aab 100644 --- a/b2g/components/test/unit/test_logshake.js +++ b/b2g/components/test/unit/test_logshake.js @@ -10,7 +10,7 @@ /* jshint -W097 */ "use strict"; -var Cu = Components.utils; +const Cu = Components.utils; Cu.import("resource://gre/modules/LogCapture.jsm"); Cu.import("resource://gre/modules/LogShake.jsm"); diff --git a/b2g/simulator/bootstrap.js b/b2g/simulator/bootstrap.js index 04f80950a779..0020815151ba 100644 --- a/b2g/simulator/bootstrap.js +++ b/b2g/simulator/bootstrap.js @@ -1,5 +1,5 @@ -var Ci = Components.interfaces; -var Cu = Components.utils; +const Ci = Components.interfaces; +const Cu = Components.utils; Cu.import("resource://gre/modules/Services.jsm"); diff --git a/browser/base/content/aboutaccounts/aboutaccounts.js b/browser/base/content/aboutaccounts/aboutaccounts.js index 046f86434833..2b95aa3ea606 100644 --- a/browser/base/content/aboutaccounts/aboutaccounts.js +++ b/browser/base/content/aboutaccounts/aboutaccounts.js @@ -4,7 +4,7 @@ "use strict"; -var {classes: Cc, interfaces: Ci, utils: Cu} = Components; +const {classes: Cc, interfaces: Ci, utils: Cu} = Components; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/FxAccounts.jsm"); diff --git a/browser/base/content/abouthealthreport/abouthealth.js b/browser/base/content/abouthealthreport/abouthealth.js index 55669edc473e..1d48231d842f 100644 --- a/browser/base/content/abouthealthreport/abouthealth.js +++ b/browser/base/content/abouthealthreport/abouthealth.js @@ -4,7 +4,7 @@ "use strict"; -var {classes: Cc, interfaces: Ci, utils: Cu} = Components; +const {classes: Cc, interfaces: Ci, utils: Cu} = Components; Cu.import("resource://gre/modules/Preferences.jsm"); Cu.import("resource://gre/modules/Services.jsm"); diff --git a/browser/base/content/pageinfo/pageInfo.js b/browser/base/content/pageinfo/pageInfo.js index e89315cfbbe1..3fceebb71c20 100644 --- a/browser/base/content/pageinfo/pageInfo.js +++ b/browser/base/content/pageinfo/pageInfo.js @@ -2,7 +2,7 @@ * 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 Cu = Components.utils; +const Cu = Components.utils; Cu.import("resource://gre/modules/LoadContextInfo.jsm"); Cu.import("resource://gre/modules/Services.jsm"); diff --git a/browser/base/content/sanitizeDialog.js b/browser/base/content/sanitizeDialog.js index 3dc3d887c5e0..77ff794864e2 100644 --- a/browser/base/content/sanitizeDialog.js +++ b/browser/base/content/sanitizeDialog.js @@ -3,11 +3,11 @@ * 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 Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; -var {Sanitizer} = Cu.import("resource:///modules/Sanitizer.jsm", {}); +let {Sanitizer} = Cu.import("resource:///modules/Sanitizer.jsm", {}); var gSanitizePromptDialog = { diff --git a/browser/base/content/social-content.js b/browser/base/content/social-content.js index f337b13c9250..db8e88222404 100644 --- a/browser/base/content/social-content.js +++ b/browser/base/content/social-content.js @@ -6,7 +6,7 @@ /* This content script should work in any browser or iframe and should not * depend on the frame being contained in tabbrowser. */ -var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); diff --git a/browser/base/content/sync/aboutSyncTabs.js b/browser/base/content/sync/aboutSyncTabs.js index f60141c9632f..08b913f30476 100644 --- a/browser/base/content/sync/aboutSyncTabs.js +++ b/browser/base/content/sync/aboutSyncTabs.js @@ -2,7 +2,7 @@ * 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 Cu = Components.utils; +const Cu = Components.utils; Cu.import("resource://services-common/utils.js"); Cu.import("resource://services-sync/main.js"); diff --git a/browser/base/content/sync/addDevice.js b/browser/base/content/sync/addDevice.js index 0390d439701a..40862a7916d9 100644 --- a/browser/base/content/sync/addDevice.js +++ b/browser/base/content/sync/addDevice.js @@ -2,9 +2,9 @@ * 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 Cu = Components.utils; +const Ci = Components.interfaces; +const Cc = Components.classes; +const Cu = Components.utils; Cu.import("resource://services-sync/main.js"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); diff --git a/browser/base/content/sync/genericChange.js b/browser/base/content/sync/genericChange.js index a71efc3f4d1d..2cd6c0e5ac23 100644 --- a/browser/base/content/sync/genericChange.js +++ b/browser/base/content/sync/genericChange.js @@ -2,8 +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/. */ -var Ci = Components.interfaces; -var Cc = Components.classes; +const Ci = Components.interfaces; +const Cc = Components.classes; Components.utils.import("resource://services-sync/main.js"); Components.utils.import("resource://gre/modules/Services.jsm"); diff --git a/browser/base/content/sync/setup.js b/browser/base/content/sync/setup.js index a38329819ef8..dd8e6f43ff8e 100644 --- a/browser/base/content/sync/setup.js +++ b/browser/base/content/sync/setup.js @@ -3,10 +3,10 @@ * 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; +const Ci = Components.interfaces; +const Cc = Components.classes; +const Cr = Components.results; +const Cu = Components.utils; // page consts diff --git a/browser/base/content/test/general/browser_aboutTabCrashed.js b/browser/base/content/test/general/browser_aboutTabCrashed.js index 95a338a468ce..bacf9d54441f 100644 --- a/browser/base/content/test/general/browser_aboutTabCrashed.js +++ b/browser/base/content/test/general/browser_aboutTabCrashed.js @@ -1,6 +1,6 @@ "use strict"; -var { TabCrashReporter } = +let { TabCrashReporter } = Cu.import("resource:///modules/ContentCrashReporters.jsm"); const SERVER_URL = "http://example.com/browser/toolkit/crashreporter/test/browser/crashreport.sjs"; diff --git a/browser/base/content/test/general/browser_alltabslistener.js b/browser/base/content/test/general/browser_alltabslistener.js index c6550ab59aa3..aee9d6157ff5 100644 --- a/browser/base/content/test/general/browser_alltabslistener.js +++ b/browser/base/content/test/general/browser_alltabslistener.js @@ -1,4 +1,4 @@ -var Ci = Components.interfaces; +const Ci = Components.interfaces; const gCompleteState = Ci.nsIWebProgressListener.STATE_STOP + Ci.nsIWebProgressListener.STATE_IS_NETWORK; diff --git a/browser/base/content/test/general/browser_bug356571.js b/browser/base/content/test/general/browser_bug356571.js index 826def9cbd43..a94e4788a059 100644 --- a/browser/base/content/test/general/browser_bug356571.js +++ b/browser/base/content/test/general/browser_bug356571.js @@ -1,7 +1,7 @@ // Bug 356571 - loadOneOrMoreURIs gives up if one of the URLs has an unknown protocol -var Cr = Components.results; -var Cm = Components.manager; +const Cr = Components.results; +const Cm = Components.manager; // Set to true when docShell alerts for unknown protocol error var didFail = false; diff --git a/browser/base/content/test/general/browser_bug567306.js b/browser/base/content/test/general/browser_bug567306.js index 742ff6726891..cc262d605283 100644 --- a/browser/base/content/test/general/browser_bug567306.js +++ b/browser/base/content/test/general/browser_bug567306.js @@ -2,7 +2,7 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ -var {Ci: interfaces, Cc: classes} = Components; +const {Ci: interfaces, Cc: classes} = Components; var Clipboard = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard); var HasFindClipboard = Clipboard.supportsFindClipboard(); diff --git a/browser/base/content/test/general/browser_overflowScroll.js b/browser/base/content/test/general/browser_overflowScroll.js index 56932fae27b1..d3132c7f932f 100644 --- a/browser/base/content/test/general/browser_overflowScroll.js +++ b/browser/base/content/test/general/browser_overflowScroll.js @@ -3,16 +3,16 @@ var scrollbox = tabstrip._scrollbox; var originalSmoothScroll = tabstrip.smoothScroll; var tabs = gBrowser.tabs; -var rect = ele => ele.getBoundingClientRect(); -var width = ele => rect(ele).width; -var left = ele => rect(ele).left; -var right = ele => rect(ele).right; -var isLeft = (ele, msg) => is(left(ele) + tabstrip._tabMarginLeft, left(scrollbox), msg); -var isRight = (ele, msg) => is(right(ele) - tabstrip._tabMarginRight, right(scrollbox), msg); -var elementFromPoint = x => tabstrip._elementFromPoint(x); -var nextLeftElement = () => elementFromPoint(left(scrollbox) - 1); -var nextRightElement = () => elementFromPoint(right(scrollbox) + 1); -var firstScrollable = () => tabs[gBrowser._numPinnedTabs]; +let rect = ele => ele.getBoundingClientRect(); +let width = ele => rect(ele).width; +let left = ele => rect(ele).left; +let right = ele => rect(ele).right; +let isLeft = (ele, msg) => is(left(ele) + tabstrip._tabMarginLeft, left(scrollbox), msg); +let isRight = (ele, msg) => is(right(ele) - tabstrip._tabMarginRight, right(scrollbox), msg); +let elementFromPoint = x => tabstrip._elementFromPoint(x); +let nextLeftElement = () => elementFromPoint(left(scrollbox) - 1); +let nextRightElement = () => elementFromPoint(right(scrollbox) + 1); +let firstScrollable = () => tabs[gBrowser._numPinnedTabs]; function test() { requestLongerTimeout(2); diff --git a/browser/base/content/test/general/browser_permissions.js b/browser/base/content/test/general/browser_permissions.js index 1f59a3bb62b2..87a8d3b4ba94 100644 --- a/browser/base/content/test/general/browser_permissions.js +++ b/browser/base/content/test/general/browser_permissions.js @@ -2,7 +2,7 @@ * Test the Permissions section in the Control Center. */ -var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; const PERMISSIONS_PAGE = "http://example.com/browser/browser/base/content/test/general/permissions.html"; var {SitePermissions} = Cu.import("resource:///modules/SitePermissions.jsm", {}); diff --git a/browser/base/content/test/general/browser_sanitizeDialog.js b/browser/base/content/test/general/browser_sanitizeDialog.js index d90a042d2ad0..74d2a4411665 100644 --- a/browser/base/content/test/general/browser_sanitizeDialog.js +++ b/browser/base/content/test/general/browser_sanitizeDialog.js @@ -18,7 +18,7 @@ */ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); -var {LoadContextInfo} = Cu.import("resource://gre/modules/LoadContextInfo.jsm", {}); +let {LoadContextInfo} = Cu.import("resource://gre/modules/LoadContextInfo.jsm", {}); XPCOMUtils.defineLazyModuleGetter(this, "FormHistory", "resource://gre/modules/FormHistory.jsm"); @@ -29,10 +29,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "Timer", XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils", "resource://testing-common/PlacesTestUtils.jsm"); -var tempScope = {}; +let tempScope = {}; Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader) .loadSubScript("chrome://browser/content/sanitize.js", tempScope); -var Sanitizer = tempScope.Sanitizer; +let Sanitizer = tempScope.Sanitizer; const kMsecPerMin = 60 * 1000; const kUsecPerMin = 60 * 1000000; @@ -675,8 +675,8 @@ add_task(function* test_offline_apps_permissions() { return wh.promiseClosed; }); -var now_mSec = Date.now(); -var now_uSec = now_mSec * 1000; +let now_mSec = Date.now(); +let now_uSec = now_mSec * 1000; /////////////////////////////////////////////////////////////////////////////// diff --git a/browser/base/content/test/general/browser_trackingUI_1.js b/browser/base/content/test/general/browser_trackingUI_1.js index 3dc90d8cdc66..16613f0e3e1d 100644 --- a/browser/base/content/test/general/browser_trackingUI_1.js +++ b/browser/base/content/test/general/browser_trackingUI_1.js @@ -7,7 +7,7 @@ * See also Bugs 1175327, 1043801, 1178985 */ -var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; const PREF = "privacy.trackingprotection.enabled"; const PB_PREF = "privacy.trackingprotection.pbmode.enabled"; const BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/benignPage.html"; diff --git a/browser/base/content/test/general/browser_trackingUI_2.js b/browser/base/content/test/general/browser_trackingUI_2.js index 965ec09cd876..43ee4ff3f40f 100644 --- a/browser/base/content/test/general/browser_trackingUI_2.js +++ b/browser/base/content/test/general/browser_trackingUI_2.js @@ -4,7 +4,7 @@ * See also Bugs 1175327, 1043801, 1178985. */ -var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; const PREF = "privacy.trackingprotection.enabled"; const PB_PREF = "privacy.trackingprotection.pbmode.enabled"; const BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/benignPage.html"; diff --git a/browser/base/content/test/general/browser_trackingUI_4.js b/browser/base/content/test/general/browser_trackingUI_4.js index 277763593ef6..502fe4b9cd6a 100644 --- a/browser/base/content/test/general/browser_trackingUI_4.js +++ b/browser/base/content/test/general/browser_trackingUI_4.js @@ -4,7 +4,7 @@ * See also Bug 1175858. */ -var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; const PREF = "privacy.trackingprotection.enabled"; const PB_PREF = "privacy.trackingprotection.pbmode.enabled"; const BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/benignPage.html"; diff --git a/browser/base/content/test/general/browser_trackingUI_telemetry.js b/browser/base/content/test/general/browser_trackingUI_telemetry.js index 0710d14b5102..6f3e69becb7f 100644 --- a/browser/base/content/test/general/browser_trackingUI_telemetry.js +++ b/browser/base/content/test/general/browser_trackingUI_telemetry.js @@ -2,7 +2,7 @@ * Test telemetry for Tracking Protection */ -var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; const PREF = "privacy.trackingprotection.enabled"; const BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/benignPage.html"; const TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/trackingPage.html"; diff --git a/browser/base/content/test/general/content_aboutAccounts.js b/browser/base/content/test/general/content_aboutAccounts.js index 24116af5adb4..41af7b7ee257 100644 --- a/browser/base/content/test/general/content_aboutAccounts.js +++ b/browser/base/content/test/general/content_aboutAccounts.js @@ -5,7 +5,7 @@ // This file is loaded as a "content script" for browser_aboutAccounts tests "use strict"; -var {interfaces: Ci, utils: Cu} = Components; +const {interfaces: Ci, utils: Cu} = Components; addEventListener("load", function load(event) { if (event.target != content.document) { diff --git a/browser/base/content/test/plugins/blocklist_proxy.js b/browser/base/content/test/plugins/blocklist_proxy.js index 1a4ed47264b2..c7461f042c17 100644 --- a/browser/base/content/test/plugins/blocklist_proxy.js +++ b/browser/base/content/test/plugins/blocklist_proxy.js @@ -1,7 +1,7 @@ -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; -var Cm = Components.manager; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cm = Components.manager; const kBlocklistServiceUUID = "{66354bc9-7ed1-4692-ae1d-8da97d6b205e}"; const kBlocklistServiceContractID = "@mozilla.org/extensions/blocklist;1"; diff --git a/browser/base/content/test/plugins/browser_bug797677.js b/browser/base/content/test/plugins/browser_bug797677.js index bb8490f94264..e7c59c3688cb 100644 --- a/browser/base/content/test/plugins/browser_bug797677.js +++ b/browser/base/content/test/plugins/browser_bug797677.js @@ -2,8 +2,8 @@ var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content var gTestBrowser = null; var gConsoleErrors = 0; -var Cc = Components.classes; -var Ci = Components.interfaces; +const Cc = Components.classes; +const Ci = Components.interfaces; add_task(function* () { registerCleanupFunction(function () { diff --git a/browser/base/content/webrtcIndicator.js b/browser/base/content/webrtcIndicator.js index 784cffaecfa9..6dd42e057097 100644 --- a/browser/base/content/webrtcIndicator.js +++ b/browser/base/content/webrtcIndicator.js @@ -2,7 +2,7 @@ * 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 {classes: Cc, interfaces: Ci, utils: Cu} = Components; +const {classes: Cc, interfaces: Ci, utils: Cu} = Components; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource:///modules/webrtcUI.jsm"); diff --git a/browser/components/dirprovider/tests/unit/head_dirprovider.js b/browser/components/dirprovider/tests/unit/head_dirprovider.js index b80f8ed6bb89..f6f4aac49991 100644 --- a/browser/components/dirprovider/tests/unit/head_dirprovider.js +++ b/browser/components/dirprovider/tests/unit/head_dirprovider.js @@ -2,8 +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/. */ -var Cc = Components.classes; -var Ci = Components.interfaces; +const Cc = Components.classes; +const Ci = Components.interfaces; var gProfD = do_get_profile(); var gDirSvc = Cc["@mozilla.org/file/directory_service;1"]. diff --git a/browser/components/distribution.js b/browser/components/distribution.js index b4c9e4b03835..507da77fcc1e 100644 --- a/browser/components/distribution.js +++ b/browser/components/distribution.js @@ -4,10 +4,10 @@ this.EXPORTED_SYMBOLS = [ "DistributionCustomizer" ]; -var Ci = Components.interfaces; -var Cc = Components.classes; -var Cr = Components.results; -var Cu = Components.utils; +const Ci = Components.interfaces; +const Cc = Components.classes; +const Cr = Components.results; +const Cu = Components.utils; const DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC = "distribution-customization-complete"; diff --git a/browser/components/downloads/test/unit/head.js b/browser/components/downloads/test/unit/head.js index d7ce4d48addf..7e5a708cc8c4 100644 --- a/browser/components/downloads/test/unit/head.js +++ b/browser/components/downloads/test/unit/head.js @@ -10,9 +10,9 @@ //////////////////////////////////////////////////////////////////////////////// //// Globals -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; -var Cr = Components.results; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; Cu.import("resource:///modules/DownloadsCommon.jsm"); diff --git a/browser/components/extensions/ext-browserAction.js b/browser/components/extensions/ext-browserAction.js index 6965706e8736..5f1b2437db21 100644 --- a/browser/components/extensions/ext-browserAction.js +++ b/browser/components/extensions/ext-browserAction.js @@ -17,7 +17,7 @@ var browserActionMap = new WeakMap(); // WeakMap[Extension -> docshell] // This map is a cache of the windowless browser that's used to render ImageData // for the browser_action icon. -var imageRendererMap = new WeakMap(); +let imageRendererMap = new WeakMap(); function browserActionOf(extension) { diff --git a/browser/components/extensions/ext-contextMenus.js b/browser/components/extensions/ext-contextMenus.js index 131880dcc58c..746e5561fb7e 100644 --- a/browser/components/extensions/ext-contextMenus.js +++ b/browser/components/extensions/ext-contextMenus.js @@ -3,7 +3,7 @@ Cu.import("resource://gre/modules/MatchPattern.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -var { +let { EventManager, contextMenuItems, runSafe @@ -13,13 +13,13 @@ var { // Map[Extension -> Map[ID -> MenuItem]] // Note: we want to enumerate all the menu items so // this cannot be a weak map. -var contextMenuMap = new Map(); +let contextMenuMap = new Map(); // Not really used yet, will be used for event pages. -var onClickedCallbacksMap = new WeakMap(); +let onClickedCallbacksMap = new WeakMap(); // If id is not specified for an item we use an integer. -var nextID = 0; +let nextID = 0; function contextMenuObserver(subject, topic, data) { subject = subject.wrappedJSObject; @@ -34,7 +34,7 @@ function contextMenuObserver(subject, topic, data) { // For remote processes there is a gContextMenuContentData where all // the important info is stored from the child process. We get // this data in |contentData|. -var menuBuilder = { +let menuBuilder = { build: function(contextData) { // TODO: icons should be set for items let xulMenu = contextData.menu; @@ -338,7 +338,7 @@ MenuItem.prototype = { }, }; -var extCount = 0; +let extCount = 0; extensions.on("startup", (type, extension) => { contextMenuMap.set(extension, new Map()); if (++extCount == 1) { diff --git a/browser/components/extensions/test/browser/head.js b/browser/components/extensions/test/browser/head.js index ac6f9c17ffdc..d4fccd609472 100644 --- a/browser/components/extensions/test/browser/head.js +++ b/browser/components/extensions/test/browser/head.js @@ -1,4 +1,4 @@ -var {CustomizableUI} = Cu.import("resource:///modules/CustomizableUI.jsm"); +let {CustomizableUI} = Cu.import("resource:///modules/CustomizableUI.jsm"); function makeWidgetId(id) { diff --git a/browser/components/feeds/test/unit/head_feeds.js b/browser/components/feeds/test/unit/head_feeds.js index 3b1135ef7be7..841f68157e32 100644 --- a/browser/components/feeds/test/unit/head_feeds.js +++ b/browser/components/feeds/test/unit/head_feeds.js @@ -1,5 +1,5 @@ -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cr = Components.results; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cr = Components.results; var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); diff --git a/browser/components/feeds/test/unit/test_355473.js b/browser/components/feeds/test/unit/test_355473.js index 97f5d088520e..9b09c76c3f44 100644 --- a/browser/components/feeds/test/unit/test_355473.js +++ b/browser/components/feeds/test/unit/test_355473.js @@ -1,4 +1,4 @@ -var Cu = Components.utils; +const Cu = Components.utils; Cu.import("resource://gre/modules/Services.jsm"); function run_test() { diff --git a/browser/components/loop/test/xpcshell/head.js b/browser/components/loop/test/xpcshell/head.js index 97ad9c109c11..91742dd540b9 100644 --- a/browser/components/loop/test/xpcshell/head.js +++ b/browser/components/loop/test/xpcshell/head.js @@ -3,7 +3,7 @@ "use strict"; -var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; // Initialize this before the imports, as some of them need it. do_get_profile(); diff --git a/browser/components/migration/IEProfileMigrator.js b/browser/components/migration/IEProfileMigrator.js index 4ad9d978df67..fa03b9f35e44 100644 --- a/browser/components/migration/IEProfileMigrator.js +++ b/browser/components/migration/IEProfileMigrator.js @@ -32,7 +32,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "WindowsRegistry", Cu.importGlobalProperties(["URL"]); -var CtypesKernelHelpers = MSMigrationUtils.CtypesKernelHelpers; +let CtypesKernelHelpers = MSMigrationUtils.CtypesKernelHelpers; //////////////////////////////////////////////////////////////////////////////// //// Resources diff --git a/browser/components/migration/content/migration.js b/browser/components/migration/content/migration.js index 44dbdfeb8097..fd0c3d534c5c 100644 --- a/browser/components/migration/content/migration.js +++ b/browser/components/migration/content/migration.js @@ -2,9 +2,9 @@ * 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 Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; const kIMig = Ci.nsIBrowserProfileMigrator; const kIPStartup = Ci.nsIProfileStartup; diff --git a/browser/components/migration/tests/unit/head_migration.js b/browser/components/migration/tests/unit/head_migration.js index d56bda2b975c..bcad3546116a 100644 --- a/browser/components/migration/tests/unit/head_migration.js +++ b/browser/components/migration/tests/unit/head_migration.js @@ -1,4 +1,4 @@ -var { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components; +const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components; Cu.importGlobalProperties([ "URL" ]); diff --git a/browser/components/places/tests/unit/head_bookmarks.js b/browser/components/places/tests/unit/head_bookmarks.js index 9936b7e923f4..d5e4f22c89e2 100644 --- a/browser/components/places/tests/unit/head_bookmarks.js +++ b/browser/components/places/tests/unit/head_bookmarks.js @@ -3,10 +3,10 @@ * 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; +const Ci = Components.interfaces; +const Cc = Components.classes; +const Cr = Components.results; +const Cu = Components.utils; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/LoadContextInfo.jsm"); diff --git a/browser/components/preferences/blocklists.js b/browser/components/preferences/blocklists.js index 06bdfaf7e0f0..19159c1e4876 100644 --- a/browser/components/preferences/blocklists.js +++ b/browser/components/preferences/blocklists.js @@ -8,7 +8,7 @@ const TRACK_SUFFIX = "-track-digest256"; const TRACKING_TABLE_PREF = "urlclassifier.trackingTable"; const LISTS_PREF_BRANCH = "browser.safebrowsing.provider.mozilla.lists."; -var gBlocklistManager = { +let gBlocklistManager = { _type: "", _blockLists: [], _brandShortName : null, diff --git a/browser/components/preferences/in-content/preferences.js b/browser/components/preferences/in-content/preferences.js index aa6a1713b12e..6018cb87a5c1 100644 --- a/browser/components/preferences/in-content/preferences.js +++ b/browser/components/preferences/in-content/preferences.js @@ -4,10 +4,10 @@ "use strict"; -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; -var Cr = Components.results; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); diff --git a/browser/components/preferences/translation.js b/browser/components/preferences/translation.js index 6610561dc178..c13001c3dcdd 100644 --- a/browser/components/preferences/translation.js +++ b/browser/components/preferences/translation.js @@ -5,7 +5,7 @@ "use strict"; -var {classes: Cc, interfaces: Ci, utils: Cu} = Components; +const {classes: Cc, interfaces: Ci, utils: Cu} = Components; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); diff --git a/browser/components/privatebrowsing/content/aboutPrivateBrowsing.js b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.js index 6673bc956edc..1ae0621acdd0 100644 --- a/browser/components/privatebrowsing/content/aboutPrivateBrowsing.js +++ b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.js @@ -2,7 +2,7 @@ * 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 {classes: Cc, interfaces: Ci, utils: Cu} = Components; +const {classes: Cc, interfaces: Ci, utils: Cu} = Components; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm"); diff --git a/browser/components/sessionstore/content/aboutSessionRestore.js b/browser/components/sessionstore/content/aboutSessionRestore.js index 92c4d88b09a5..097de107c8ec 100644 --- a/browser/components/sessionstore/content/aboutSessionRestore.js +++ b/browser/components/sessionstore/content/aboutSessionRestore.js @@ -4,7 +4,7 @@ "use strict"; -var {classes: Cc, interfaces: Ci, utils: Cu} = Components; +const {classes: Cc, interfaces: Ci, utils: Cu} = Components; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); diff --git a/browser/components/shell/test/unit/test_421977.js b/browser/components/shell/test/unit/test_421977.js index 3d1474239f52..da7c0d7b97be 100644 --- a/browser/components/shell/test/unit/test_421977.js +++ b/browser/components/shell/test/unit/test_421977.js @@ -1,6 +1,6 @@ -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cr = Components.results; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cr = Components.results; const GCONF_BG_COLOR_KEY = "/desktop/gnome/background/primary_color"; diff --git a/browser/components/tabview/tabview.js b/browser/components/tabview/tabview.js index a636aa2f9a68..4bf37d74c775 100644 --- a/browser/components/tabview/tabview.js +++ b/browser/components/tabview/tabview.js @@ -4,10 +4,10 @@ "use strict"; -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; -var Cr = Components.results; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; Cu.import("resource:///modules/tabview/utils.jsm"); Cu.import("resource://gre/modules/AppConstants.jsm"); diff --git a/browser/components/uitour/test/browser_fxa.js b/browser/components/uitour/test/browser_fxa.js index 36ac45a62450..77a763c74c7d 100644 --- a/browser/components/uitour/test/browser_fxa.js +++ b/browser/components/uitour/test/browser_fxa.js @@ -3,7 +3,7 @@ "use strict"; -var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts", "resource://gre/modules/FxAccounts.jsm"); diff --git a/browser/components/uitour/test/browser_openPreferences.js b/browser/components/uitour/test/browser_openPreferences.js index b3a8b71f32d2..4e0fdc14383d 100644 --- a/browser/components/uitour/test/browser_openPreferences.js +++ b/browser/components/uitour/test/browser_openPreferences.js @@ -3,7 +3,7 @@ "use strict"; -var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; var gTestTab; var gContentAPI; diff --git a/browser/components/uitour/test/browser_showMenu_controlCenter.js b/browser/components/uitour/test/browser_showMenu_controlCenter.js index d111481cbeda..73c567e648ec 100644 --- a/browser/components/uitour/test/browser_showMenu_controlCenter.js +++ b/browser/components/uitour/test/browser_showMenu_controlCenter.js @@ -1,6 +1,6 @@ "use strict"; -var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; const CONTROL_CENTER_PANEL = gIdentityHandler._identityPopup; const CONTROL_CENTER_MENU_NAME = "controlCenter"; diff --git a/browser/components/uitour/test/browser_trackingProtection.js b/browser/components/uitour/test/browser_trackingProtection.js index 1f4e8ef6126e..f82427266fff 100644 --- a/browser/components/uitour/test/browser_trackingProtection.js +++ b/browser/components/uitour/test/browser_trackingProtection.js @@ -1,6 +1,6 @@ "use strict"; -var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; const PREF_INTRO_COUNT = "privacy.trackingprotection.introCount"; const PREF_TP_ENABLED = "privacy.trackingprotection.enabled"; const BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/benignPage.html"; diff --git a/browser/experiments/test/xpcshell/head.js b/browser/experiments/test/xpcshell/head.js index 40eb9aa01a9f..895c60e4c12b 100644 --- a/browser/experiments/test/xpcshell/head.js +++ b/browser/experiments/test/xpcshell/head.js @@ -1,7 +1,7 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ -var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); diff --git a/browser/modules/Chat.jsm b/browser/modules/Chat.jsm index 30ac29224bf0..671c20ef6886 100644 --- a/browser/modules/Chat.jsm +++ b/browser/modules/Chat.jsm @@ -18,7 +18,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; const kDefaultButtonSet = new Set(["minimize", "swap", "close"]); const kHiddenDefaultButtons = new Set(["minimize", "close"]); -var gCustomButtons = new Map(); +let gCustomButtons = new Map(); // A couple of internal helper function. function isWindowChromeless(win) { diff --git a/browser/modules/Sanitizer.jsm b/browser/modules/Sanitizer.jsm index 31c2823c7fd2..cf9ea474a8ab 100644 --- a/browser/modules/Sanitizer.jsm +++ b/browser/modules/Sanitizer.jsm @@ -15,7 +15,7 @@ this.EXPORTED_SYMBOLS = ["Sanitizer"]; const { classes: Cc, interfaces: Ci, utils: Cu } = Components; -var scope = {}; +let scope = {}; Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader) .loadSubScript("chrome://browser/content/sanitize.js", scope); diff --git a/browser/modules/test/unit/social/head.js b/browser/modules/test/unit/social/head.js index 2687bd0d8d49..66348c367d58 100644 --- a/browser/modules/test/unit/social/head.js +++ b/browser/modules/test/unit/social/head.js @@ -2,7 +2,7 @@ * 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 { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); diff --git a/browser/modules/test/xpcshell/test_DirectoryLinksProvider.js b/browser/modules/test/xpcshell/test_DirectoryLinksProvider.js index b399c35ff27b..ccc1b94c42cb 100644 --- a/browser/modules/test/xpcshell/test_DirectoryLinksProvider.js +++ b/browser/modules/test/xpcshell/test_DirectoryLinksProvider.js @@ -7,7 +7,7 @@ * This file tests the DirectoryLinksProvider singleton in the DirectoryLinksProvider.jsm module. */ -var { classes: Cc, interfaces: Ci, results: Cr, utils: Cu, Constructor: CC } = Components; +const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu, Constructor: CC } = Components; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource:///modules/DirectoryLinksProvider.jsm"); Cu.import("resource://gre/modules/Promise.jsm"); diff --git a/caps/tests/unit/test_origin.js b/caps/tests/unit/test_origin.js index 511837f8c674..da26b70d0e9b 100644 --- a/caps/tests/unit/test_origin.js +++ b/caps/tests/unit/test_origin.js @@ -1,6 +1,6 @@ -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; Cu.import("resource://gre/modules/Services.jsm"); var ssm = Services.scriptSecurityManager; diff --git a/chrome/test/unit/head_crtestutils.js b/chrome/test/unit/head_crtestutils.js index d4447c55533a..d5679048030d 100644 --- a/chrome/test/unit/head_crtestutils.js +++ b/chrome/test/unit/head_crtestutils.js @@ -1,9 +1,9 @@ const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1"; const XULAPPINFO_CID = Components.ID("{4ba645d3-be6f-40d6-a42a-01b2f40091b8}"); -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cr = Components.results; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cr = Components.results; function registerManifests(manifests) diff --git a/devtools/client/aboutdebugging/aboutdebugging.js b/devtools/client/aboutdebugging/aboutdebugging.js index dbb0321521a7..f349c3406e84 100644 --- a/devtools/client/aboutdebugging/aboutdebugging.js +++ b/devtools/client/aboutdebugging/aboutdebugging.js @@ -21,7 +21,7 @@ loader.lazyRequireGetter(this, "WorkersComponent", "devtools/client/aboutdebugging/components/workers", true); loader.lazyRequireGetter(this, "Services"); -var AboutDebugging = { +let AboutDebugging = { _categories: null, get categories() { // If needed, initialize the list of available categories. diff --git a/devtools/client/animationinspector/animation-controller.js b/devtools/client/animationinspector/animation-controller.js index 514a970abbba..dd5e0ecd346e 100644 --- a/devtools/client/animationinspector/animation-controller.js +++ b/devtools/client/animationinspector/animation-controller.js @@ -7,7 +7,7 @@ "use strict"; -var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; Cu.import("resource://gre/modules/Task.jsm"); var { loader, require } = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm"); diff --git a/devtools/client/animationinspector/test/head.js b/devtools/client/animationinspector/test/head.js index e3c9fcfa8837..61be58fe547c 100644 --- a/devtools/client/animationinspector/test/head.js +++ b/devtools/client/animationinspector/test/head.js @@ -4,7 +4,7 @@ "use strict"; -var Cu = Components.utils; +const Cu = Components.utils; const {gDevTools} = Cu.import("resource:///modules/devtools/client/framework/gDevTools.jsm", {}); const {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); const promise = require("promise"); diff --git a/devtools/client/animationinspector/test/unit/test_findOptimalTimeInterval.js b/devtools/client/animationinspector/test/unit/test_findOptimalTimeInterval.js index 08bc1cbf8b56..5543ffa95878 100644 --- a/devtools/client/animationinspector/test/unit/test_findOptimalTimeInterval.js +++ b/devtools/client/animationinspector/test/unit/test_findOptimalTimeInterval.js @@ -6,7 +6,7 @@ "use strict"; -var Cu = Components.utils; +const Cu = Components.utils; const {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); const {findOptimalTimeInterval} = require("devtools/client/animationinspector/utils"); diff --git a/devtools/client/animationinspector/test/unit/test_timeScale.js b/devtools/client/animationinspector/test/unit/test_timeScale.js index afb33337ae7f..26c137b30727 100644 --- a/devtools/client/animationinspector/test/unit/test_timeScale.js +++ b/devtools/client/animationinspector/test/unit/test_timeScale.js @@ -5,7 +5,7 @@ "use strict"; -var Cu = Components.utils; +const Cu = Components.utils; const {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); const {TimeScale} = require("devtools/client/animationinspector/components"); diff --git a/devtools/client/app-manager/content/connection-footer.js b/devtools/client/app-manager/content/connection-footer.js index d04b34d82922..31ac3e973a24 100644 --- a/devtools/client/app-manager/content/connection-footer.js +++ b/devtools/client/app-manager/content/connection-footer.js @@ -2,8 +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/. */ -var Cu = Components.utils; -var Ci = Components.interfaces; +const Cu = Components.utils; +const Ci = Components.interfaces; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource:///modules/devtools/client/framework/gDevTools.jsm"); diff --git a/devtools/client/app-manager/content/device.js b/devtools/client/app-manager/content/device.js index b0abefa5901a..95b145026c5d 100644 --- a/devtools/client/app-manager/content/device.js +++ b/devtools/client/app-manager/content/device.js @@ -2,7 +2,7 @@ * 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 Cu = Components.utils; +const Cu = Components.utils; Cu.import("resource://gre/modules/Services.jsm"); const {gDevTools} = Cu.import("resource:///modules/devtools/client/framework/gDevTools.jsm", {}); diff --git a/devtools/client/app-manager/content/index.js b/devtools/client/app-manager/content/index.js index 99c91038d4dc..cbe980f49de5 100644 --- a/devtools/client/app-manager/content/index.js +++ b/devtools/client/app-manager/content/index.js @@ -2,7 +2,7 @@ * 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 {utils: Cu, interfaces: Ci} = Components; +const {utils: Cu, interfaces: Ci} = Components; Cu.import("resource:///modules/devtools/client/framework/gDevTools.jsm"); const {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); const {Toolbox} = require("devtools/client/framework/toolbox"); diff --git a/devtools/client/app-manager/content/projects.js b/devtools/client/app-manager/content/projects.js index 11eeeda84203..58df1cb36906 100644 --- a/devtools/client/app-manager/content/projects.js +++ b/devtools/client/app-manager/content/projects.js @@ -2,10 +2,10 @@ * 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 Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; -var Cr = Components.results; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; Cu.import("resource:///modules/devtools/client/framework/gDevTools.jsm"); const {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); const {ConnectionManager, Connection} = require("devtools/shared/client/connection-manager"); diff --git a/devtools/client/app-manager/test/head.js b/devtools/client/app-manager/test/head.js index 6607da4333b5..450c5fe50793 100644 --- a/devtools/client/app-manager/test/head.js +++ b/devtools/client/app-manager/test/head.js @@ -2,7 +2,7 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; -var {utils: Cu, classes: Cc, interfaces: Ci} = Components; +const {utils: Cu, classes: Cc, interfaces: Ci} = Components; const {Promise: promise} = Cu.import("resource://gre/modules/devtools/shared/deprecated-sync-thenables.js", {}); diff --git a/devtools/client/canvasdebugger/canvasdebugger.js b/devtools/client/canvasdebugger/canvasdebugger.js index 52e5eff278e6..c39bd04dc212 100644 --- a/devtools/client/canvasdebugger/canvasdebugger.js +++ b/devtools/client/canvasdebugger/canvasdebugger.js @@ -3,7 +3,7 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; -var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); diff --git a/devtools/client/canvasdebugger/test/head.js b/devtools/client/canvasdebugger/test/head.js index 573e064e7ba2..770e7ec901c0 100644 --- a/devtools/client/canvasdebugger/test/head.js +++ b/devtools/client/canvasdebugger/test/head.js @@ -2,7 +2,7 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; -var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; var { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); diff --git a/devtools/client/debugger/debugger-controller.js b/devtools/client/debugger/debugger-controller.js index b158fdf50a7c..6fc0137b6ff2 100644 --- a/devtools/client/debugger/debugger-controller.js +++ b/devtools/client/debugger/debugger-controller.js @@ -5,7 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; -var { classes: Cc, interfaces: Ci, utils: Cu } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; const DBG_STRINGS_URI = "chrome://browser/locale/devtools/debugger.properties"; const NEW_SOURCE_IGNORED_URLS = ["debugger eval code", "XStringBundle"]; diff --git a/devtools/client/debugger/test/mochitest/addon-source/browser_dbg_addon4/bootstrap.js b/devtools/client/debugger/test/mochitest/addon-source/browser_dbg_addon4/bootstrap.js index d5698a8e200a..360468ab2f86 100644 --- a/devtools/client/debugger/test/mochitest/addon-source/browser_dbg_addon4/bootstrap.js +++ b/devtools/client/debugger/test/mochitest/addon-source/browser_dbg_addon4/bootstrap.js @@ -1,7 +1,7 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ -var { interfaces: Ci, classes: Cc, utils: Cu } = Components; +const { interfaces: Ci, classes: Cc, utils: Cu } = Components; function notify() { // Log objects so makeDebuggeeValue can get the global to use diff --git a/devtools/client/debugger/test/mochitest/addon-source/browser_dbg_addon5/bootstrap.js b/devtools/client/debugger/test/mochitest/addon-source/browser_dbg_addon5/bootstrap.js index 8edc53756c41..c8f89bd34924 100644 --- a/devtools/client/debugger/test/mochitest/addon-source/browser_dbg_addon5/bootstrap.js +++ b/devtools/client/debugger/test/mochitest/addon-source/browser_dbg_addon5/bootstrap.js @@ -1,7 +1,7 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ -var { interfaces: Ci, classes: Cc } = Components; +const { interfaces: Ci, classes: Cc } = Components; function startup(aParams, aReason) { Components.utils.import("resource://gre/modules/Services.jsm"); diff --git a/devtools/client/debugger/test/mochitest/code_frame-script.js b/devtools/client/debugger/test/mochitest/code_frame-script.js index 479ab3d9cbc8..a763c0976b42 100644 --- a/devtools/client/debugger/test/mochitest/code_frame-script.js +++ b/devtools/client/debugger/test/mochitest/code_frame-script.js @@ -1,6 +1,6 @@ "use strict"; -var { classes: Cc, interfaces: Ci, utils: Cu } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; const { loadSubScript } = Cc['@mozilla.org/moz/jssubscript-loader;1']. getService(Ci.mozIJSSubScriptLoader); diff --git a/devtools/client/debugger/test/mochitest/head.js b/devtools/client/debugger/test/mochitest/head.js index 4f5f333583e6..1e6948caa3ee 100644 --- a/devtools/client/debugger/test/mochitest/head.js +++ b/devtools/client/debugger/test/mochitest/head.js @@ -2,7 +2,7 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; -var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; var { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); diff --git a/devtools/client/fontinspector/font-inspector.js b/devtools/client/fontinspector/font-inspector.js index 30608550ac0a..c47be2e92859 100644 --- a/devtools/client/fontinspector/font-inspector.js +++ b/devtools/client/fontinspector/font-inspector.js @@ -6,7 +6,7 @@ "use strict"; -var { utils: Cu } = Components; +const { utils: Cu } = Components; const DEFAULT_PREVIEW_TEXT = "Abc"; const PREVIEW_UPDATE_DELAY = 150; diff --git a/devtools/client/framework/connect/connect.js b/devtools/client/framework/connect/connect.js index b926e4f25dec..2ba25b827bad 100644 --- a/devtools/client/framework/connect/connect.js +++ b/devtools/client/framework/connect/connect.js @@ -6,7 +6,7 @@ "use strict"; -var Cu = Components.utils; +const Cu = Components.utils; Cu.import('resource://gre/modules/XPCOMUtils.jsm'); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/Task.jsm"); diff --git a/devtools/client/framework/test/shared-head.js b/devtools/client/framework/test/shared-head.js index 728027eefb52..09fd9479d90e 100644 --- a/devtools/client/framework/test/shared-head.js +++ b/devtools/client/framework/test/shared-head.js @@ -4,7 +4,7 @@ // This shared-head.js file is used for multiple directories in devtools. -var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; function scopedCuImport(path) { const scope = {}; diff --git a/devtools/client/framework/toolbox-process-window.js b/devtools/client/framework/toolbox-process-window.js index c5c8f0b23c95..10f963e017cf 100644 --- a/devtools/client/framework/toolbox-process-window.js +++ b/devtools/client/framework/toolbox-process-window.js @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; -var { classes: Cc, interfaces: Ci, utils: Cu } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; var { gDevTools } = Cu.import("resource:///modules/devtools/client/framework/gDevTools.jsm", {}); var { require } = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); diff --git a/devtools/client/inspector/test/head.js b/devtools/client/inspector/test/head.js index fd87a96d2ff6..f4dfae0306c9 100644 --- a/devtools/client/inspector/test/head.js +++ b/devtools/client/inspector/test/head.js @@ -4,10 +4,10 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; -var Cu = Components.utils; -var Ci = Components.interfaces; -var Cc = Components.classes; -var CC = Components.Constructor; +const Cu = Components.utils; +const Ci = Components.interfaces; +const Cc = Components.classes; +const CC = Components.Constructor; // Services.prefs.setBoolPref("devtools.debugger.log", true); // SimpleTest.registerCleanupFunction(() => { diff --git a/devtools/client/layoutview/test/head.js b/devtools/client/layoutview/test/head.js index 2ea85ce21498..971c2efae146 100644 --- a/devtools/client/layoutview/test/head.js +++ b/devtools/client/layoutview/test/head.js @@ -4,7 +4,7 @@ "use strict"; -var Cu = Components.utils; +const Cu = Components.utils; var {gDevTools} = Cu.import("resource:///modules/devtools/client/framework/gDevTools.jsm", {}); var {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); var {console} = Cu.import("resource://gre/modules/devtools/shared/Console.jsm", {}); diff --git a/devtools/client/layoutview/view.js b/devtools/client/layoutview/view.js index 8313b867c76e..6d6b1820417f 100644 --- a/devtools/client/layoutview/view.js +++ b/devtools/client/layoutview/view.js @@ -6,7 +6,7 @@ "use strict"; -var {utils: Cu, interfaces: Ci, classes: Cc} = Components; +const {utils: Cu, interfaces: Ci, classes: Cc} = Components; Cu.import("resource://gre/modules/Task.jsm"); const {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); diff --git a/devtools/client/markupview/test/frame-script-utils.js b/devtools/client/markupview/test/frame-script-utils.js index b004e38d4d9e..7a5c235cdf74 100644 --- a/devtools/client/markupview/test/frame-script-utils.js +++ b/devtools/client/markupview/test/frame-script-utils.js @@ -4,7 +4,7 @@ "use strict"; -var {classes: Cc, interfaces: Ci} = Components; +const {classes: Cc, interfaces: Ci} = Components; const subScriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"] .getService(Ci.mozIJSSubScriptLoader); var EventUtils = {}; diff --git a/devtools/client/markupview/test/head.js b/devtools/client/markupview/test/head.js index fdfa0bd8f4e5..f78c222b4c08 100644 --- a/devtools/client/markupview/test/head.js +++ b/devtools/client/markupview/test/head.js @@ -2,7 +2,7 @@ * 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 Cu = Components.utils; +const Cu = Components.utils; var {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); var {TargetFactory} = require("devtools/client/framework/target"); var {console} = Cu.import("resource://gre/modules/devtools/shared/Console.jsm", {}); diff --git a/devtools/client/memory/initializer.js b/devtools/client/memory/initializer.js index eddbc27de6c3..6c829dff7c7e 100644 --- a/devtools/client/memory/initializer.js +++ b/devtools/client/memory/initializer.js @@ -3,7 +3,7 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; -var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; const { require } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); const { Task } = require("resource://gre/modules/Task.jsm"); const { MemoryController } = require("devtools/client/memory/controller"); @@ -11,7 +11,7 @@ const { MemoryController } = require("devtools/client/memory/controller"); /** * The current target, toolbox and MemoryFront, set by this tool's host. */ -var gToolbox, gTarget, gFront; +let gToolbox, gTarget, gFront; /** * Initializes the profiler controller and views. diff --git a/devtools/client/memory/test/mochitest/head.js b/devtools/client/memory/test/mochitest/head.js index 886fb8e22e14..7fa26b9b167c 100644 --- a/devtools/client/memory/test/mochitest/head.js +++ b/devtools/client/memory/test/mochitest/head.js @@ -3,10 +3,10 @@ "use strict"; -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; -var Cr = Components.results; -var CC = Components.Constructor; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; +const CC = Components.Constructor; const { require } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); diff --git a/devtools/client/memory/test/unit/test_action-take-snapshot.js b/devtools/client/memory/test/unit/test_action-take-snapshot.js index b4646e2d0085..ca81e16ea876 100644 --- a/devtools/client/memory/test/unit/test_action-take-snapshot.js +++ b/devtools/client/memory/test/unit/test_action-take-snapshot.js @@ -5,7 +5,7 @@ * Tests the async action creator `takeSnapshot(front)` */ -var actions = require("devtools/client/memory/actions/snapshot"); +let actions = require("devtools/client/memory/actions/snapshot"); function run_test() { run_next_test(); diff --git a/devtools/client/netmonitor/netmonitor-controller.js b/devtools/client/netmonitor/netmonitor-controller.js index 7df2ba92b07c..409d4d63d8b4 100644 --- a/devtools/client/netmonitor/netmonitor-controller.js +++ b/devtools/client/netmonitor/netmonitor-controller.js @@ -5,7 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; -var { classes: Cc, interfaces: Ci, utils: Cu } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; const NET_STRINGS_URI = "chrome://browser/locale/devtools/netmonitor.properties"; const PKI_STRINGS_URI = "chrome://pippki/locale/pippki.properties"; diff --git a/devtools/client/netmonitor/test/head.js b/devtools/client/netmonitor/test/head.js index dd2ff36e5c07..be1337686489 100644 --- a/devtools/client/netmonitor/test/head.js +++ b/devtools/client/netmonitor/test/head.js @@ -2,7 +2,7 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; -var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; var { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); var { Task } = Cu.import("resource://gre/modules/Task.jsm", {}); diff --git a/devtools/client/performance/performance-controller.js b/devtools/client/performance/performance-controller.js index 1c8b4ee8188d..1548503cb00c 100644 --- a/devtools/client/performance/performance-controller.js +++ b/devtools/client/performance/performance-controller.js @@ -3,7 +3,7 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; -var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; const { loader, require } = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); const { Task } = require("resource://gre/modules/Task.jsm"); diff --git a/devtools/client/performance/test/browser_perf-private-browsing.js b/devtools/client/performance/test/browser_perf-private-browsing.js index c43d4a0b368a..e7ee16c64145 100644 --- a/devtools/client/performance/test/browser_perf-private-browsing.js +++ b/devtools/client/performance/test/browser_perf-private-browsing.js @@ -5,7 +5,7 @@ * Tests that disables the frontend when in private browsing mode. */ -var gPanelWinTuples = []; +let gPanelWinTuples = []; function* spawnTest() { yield testNormalWindow(); diff --git a/devtools/client/performance/test/head.js b/devtools/client/performance/test/head.js index cc304f80c06e..26ce5a3d6529 100644 --- a/devtools/client/performance/test/head.js +++ b/devtools/client/performance/test/head.js @@ -2,7 +2,7 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; -var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; var { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); var { Preferences } = Cu.import("resource://gre/modules/Preferences.jsm", {}); diff --git a/devtools/client/performance/test/unit/head.js b/devtools/client/performance/test/unit/head.js index bb3b362dfc48..fcfdd59792ae 100644 --- a/devtools/client/performance/test/unit/head.js +++ b/devtools/client/performance/test/unit/head.js @@ -2,7 +2,7 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; -var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; var { require } = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); var { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); diff --git a/devtools/client/projecteditor/chrome/content/projecteditor-loader.js b/devtools/client/projecteditor/chrome/content/projecteditor-loader.js index 4f1f25043d98..83507b95be1c 100644 --- a/devtools/client/projecteditor/chrome/content/projecteditor-loader.js +++ b/devtools/client/projecteditor/chrome/content/projecteditor-loader.js @@ -1,4 +1,4 @@ -var Cu = Components.utils; +const Cu = Components.utils; const {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm", {}); const {NetUtil} = Cu.import("resource://gre/modules/NetUtil.jsm", {}); diff --git a/devtools/client/projecteditor/test/head.js b/devtools/client/projecteditor/test/head.js index 2dd942442508..88694a2fd686 100644 --- a/devtools/client/projecteditor/test/head.js +++ b/devtools/client/projecteditor/test/head.js @@ -2,7 +2,7 @@ * 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 Cu = Components.utils; +const Cu = Components.utils; const {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); const {TargetFactory} = require("devtools/client/framework/target"); const {console} = Cu.import("resource://gre/modules/devtools/shared/Console.jsm", {}); diff --git a/devtools/client/promisedebugger/promise-controller.js b/devtools/client/promisedebugger/promise-controller.js index a518d71c242d..90dfa6995af1 100644 --- a/devtools/client/promisedebugger/promise-controller.js +++ b/devtools/client/promisedebugger/promise-controller.js @@ -8,7 +8,7 @@ "use strict"; -var { utils: Cu } = Components; +const { utils: Cu } = Components; const { loader, require } = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); diff --git a/devtools/client/responsivedesign/responsivedesign-child.js b/devtools/client/responsivedesign/responsivedesign-child.js index 7e8ca97ea4e4..f02d5ee916db 100644 --- a/devtools/client/responsivedesign/responsivedesign-child.js +++ b/devtools/client/responsivedesign/responsivedesign-child.js @@ -2,7 +2,7 @@ * 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; +const Ci = Components.interfaces; const gDeviceSizeWasPageSize = docShell.deviceSizeIsPageSize; const gFloatingScrollbarsStylesheet = Services.io.newURI("chrome://devtools/skin/themes/floating-scrollbars.css", null, null); var gRequiresFloatingScrollbars; diff --git a/devtools/client/scratchpad/scratchpad.js b/devtools/client/scratchpad/scratchpad.js index 4b535acf830e..eec39faee36a 100644 --- a/devtools/client/scratchpad/scratchpad.js +++ b/devtools/client/scratchpad/scratchpad.js @@ -14,9 +14,9 @@ "use strict"; -var Cu = Components.utils; -var Cc = Components.classes; -var Ci = Components.interfaces; +const Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; const SCRATCHPAD_CONTEXT_CONTENT = 1; const SCRATCHPAD_CONTEXT_BROWSER = 2; diff --git a/devtools/client/shadereditor/shadereditor.js b/devtools/client/shadereditor/shadereditor.js index ae285e4ff8cb..45b04d487acd 100644 --- a/devtools/client/shadereditor/shadereditor.js +++ b/devtools/client/shadereditor/shadereditor.js @@ -3,7 +3,7 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; -var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); diff --git a/devtools/client/shadereditor/test/head.js b/devtools/client/shadereditor/test/head.js index 164b70b0b003..fe700d82b158 100644 --- a/devtools/client/shadereditor/test/head.js +++ b/devtools/client/shadereditor/test/head.js @@ -2,7 +2,7 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; -var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; var { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); diff --git a/devtools/client/shared/browser-loader.js b/devtools/client/shared/browser-loader.js index 47040fa16a60..96b23ab4f371 100644 --- a/devtools/client/shared/browser-loader.js +++ b/devtools/client/shared/browser-loader.js @@ -1,4 +1,4 @@ -var { classes: Cc, interfaces: Ci, utils: Cu } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; const loaders = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {}); const devtools = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}).devtools; diff --git a/devtools/client/shared/frame-script-utils.js b/devtools/client/shared/frame-script-utils.js index 4cbea9733cfb..f939b3535d83 100644 --- a/devtools/client/shared/frame-script-utils.js +++ b/devtools/client/shared/frame-script-utils.js @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; -var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; const {require, loader} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); const promise = require("promise"); loader.lazyImporter(this, "Task", "resource://gre/modules/Task.jsm", "Task"); diff --git a/devtools/client/shared/test/browser_layoutHelpers-getBoxQuads.js b/devtools/client/shared/test/browser_layoutHelpers-getBoxQuads.js index b42dc07bb42e..c3c9199a9491 100644 --- a/devtools/client/shared/test/browser_layoutHelpers-getBoxQuads.js +++ b/devtools/client/shared/test/browser_layoutHelpers-getBoxQuads.js @@ -4,8 +4,8 @@ // Tests getAdjustedQuads works properly in a variety of use cases including // iframes, scroll and zoom -var {utils: Cu} = Components; -var {getAdjustedQuads} = require("devtools/shared/layout/utils"); +const {utils: Cu} = Components; +let {getAdjustedQuads} = require("devtools/shared/layout/utils"); const TEST_URI = TEST_URI_ROOT + "browser_layoutHelpers-getBoxQuads.html"; diff --git a/devtools/client/shared/test/browser_layoutHelpers.js b/devtools/client/shared/test/browser_layoutHelpers.js index 021c830049f7..a5abb4407e2f 100644 --- a/devtools/client/shared/test/browser_layoutHelpers.js +++ b/devtools/client/shared/test/browser_layoutHelpers.js @@ -2,7 +2,7 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ // Tests that scrollIntoViewIfNeeded works properly. -var {scrollIntoViewIfNeeded} = require("devtools/shared/layout/utils"); +let {scrollIntoViewIfNeeded} = require("devtools/shared/layout/utils"); const TEST_URI = TEST_URI_ROOT + "browser_layoutHelpers.html"; diff --git a/devtools/client/shared/test/test-actor.js b/devtools/client/shared/test/test-actor.js index fb26a93528bb..52d51117d62b 100644 --- a/devtools/client/shared/test/test-actor.js +++ b/devtools/client/shared/test/test-actor.js @@ -6,7 +6,7 @@ // A helper actor for brower/devtools/inspector tests. -var { Cc, Ci, Cu, Cr } = require("chrome"); +let { Cc, Ci, Cu, Cr } = require("chrome"); const {getRect, getElementFromPoint, getAdjustedQuads} = require("devtools/shared/layout/utils"); const promise = require("promise"); const {Task} = Cu.import("resource://gre/modules/Task.jsm", {}); diff --git a/devtools/client/shared/test/unit/test_VariablesView_filtering-without-controller.js b/devtools/client/shared/test/unit/test_VariablesView_filtering-without-controller.js index b4be12e1ea74..484e61a590e8 100644 --- a/devtools/client/shared/test/unit/test_VariablesView_filtering-without-controller.js +++ b/devtools/client/shared/test/unit/test_VariablesView_filtering-without-controller.js @@ -6,9 +6,9 @@ // Test that VariablesView._doSearch() works even without an attached // VariablesViewController (bug 1196341). -var Cu = Components.utils; -var Cc = Components.classes; -var Ci = Components.interfaces; +const Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; const DOMParser = Cc["@mozilla.org/xmlextras/domparser;1"] .createInstance(Ci.nsIDOMParser); const { VariablesView } = diff --git a/devtools/client/shared/test/unit/test_VariablesView_getString_promise.js b/devtools/client/shared/test/unit/test_VariablesView_getString_promise.js index c87f6e5b1acd..ddc86b97301e 100644 --- a/devtools/client/shared/test/unit/test_VariablesView_getString_promise.js +++ b/devtools/client/shared/test/unit/test_VariablesView_getString_promise.js @@ -3,7 +3,7 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ -var Cu = Components.utils; +const Cu = Components.utils; const { VariablesView } = Cu.import("resource:///modules/devtools/client/shared/widgets/VariablesView.jsm", {}); const PENDING = { diff --git a/devtools/client/shared/test/unit/test_advanceValidate.js b/devtools/client/shared/test/unit/test_advanceValidate.js index 2b808bbfe3b0..14e3c3543834 100644 --- a/devtools/client/shared/test/unit/test_advanceValidate.js +++ b/devtools/client/shared/test/unit/test_advanceValidate.js @@ -7,8 +7,8 @@ // Tests the advanceValidate function from rule-view.js. -var Cu = Components.utils; -var Ci = Components.interfaces; +const Cu = Components.utils; +const Ci = Components.interfaces; var {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); var {advanceValidate} = require("devtools/client/styleinspector/utils"); diff --git a/devtools/client/shared/test/unit/test_attribute-parsing-01.js b/devtools/client/shared/test/unit/test_attribute-parsing-01.js index 89c59f02d7ef..19e71f972d67 100644 --- a/devtools/client/shared/test/unit/test_attribute-parsing-01.js +++ b/devtools/client/shared/test/unit/test_attribute-parsing-01.js @@ -3,7 +3,7 @@ // Test splitBy from node-attribute-parser.js -var Cu = Components.utils; +const Cu = Components.utils; var {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); const {splitBy} = require("devtools/client/shared/node-attribute-parser"); diff --git a/devtools/client/shared/test/unit/test_attribute-parsing-02.js b/devtools/client/shared/test/unit/test_attribute-parsing-02.js index f71b3a7d589e..26272ca8a0ab 100644 --- a/devtools/client/shared/test/unit/test_attribute-parsing-02.js +++ b/devtools/client/shared/test/unit/test_attribute-parsing-02.js @@ -3,7 +3,7 @@ // Test parseAttribute from node-attribute-parser.js -var Cu = Components.utils; +const Cu = Components.utils; var {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); const {parseAttribute} = require("devtools/client/shared/node-attribute-parser"); diff --git a/devtools/client/shared/test/unit/test_bezierCanvas.js b/devtools/client/shared/test/unit/test_bezierCanvas.js index 6d5456bd8e6c..b975889a7e63 100644 --- a/devtools/client/shared/test/unit/test_bezierCanvas.js +++ b/devtools/client/shared/test/unit/test_bezierCanvas.js @@ -7,7 +7,7 @@ // Tests the BezierCanvas API in the CubicBezierWidget module -var Cu = Components.utils; +const Cu = Components.utils; var {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); var {CubicBezier, BezierCanvas} = require("devtools/client/shared/widgets/CubicBezierWidget"); diff --git a/devtools/client/shared/test/unit/test_cubicBezier.js b/devtools/client/shared/test/unit/test_cubicBezier.js index 38adfbea184a..dcc987e08116 100644 --- a/devtools/client/shared/test/unit/test_cubicBezier.js +++ b/devtools/client/shared/test/unit/test_cubicBezier.js @@ -7,7 +7,7 @@ // Tests the CubicBezier API in the CubicBezierWidget module -var Cu = Components.utils; +const Cu = Components.utils; var {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); var {CubicBezier, _parseTimingFunction} = require("devtools/client/shared/widgets/CubicBezierWidget"); diff --git a/devtools/client/shared/test/unit/test_undoStack.js b/devtools/client/shared/test/unit/test_undoStack.js index 3ba619a5500b..677c09f027cc 100644 --- a/devtools/client/shared/test/unit/test_undoStack.js +++ b/devtools/client/shared/test/unit/test_undoStack.js @@ -3,7 +3,7 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ -var Cu = Components.utils; +const Cu = Components.utils; var {Loader} = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {}); var loader = new Loader.Loader({ diff --git a/devtools/client/styleeditor/test/browser_styleeditor_filesave.js b/devtools/client/styleeditor/test/browser_styleeditor_filesave.js index 4d03e60c8f9a..e5e1c248862f 100644 --- a/devtools/client/styleeditor/test/browser_styleeditor_filesave.js +++ b/devtools/client/styleeditor/test/browser_styleeditor_filesave.js @@ -8,8 +8,8 @@ const TESTCASE_URI_HTML = TEST_BASE_HTTP + "simple.html"; const TESTCASE_URI_CSS = TEST_BASE_HTTP + "simple.css"; -var Cc = Components.classes; -var Ci = Components.interfaces; +const Cc = Components.classes; +const Ci = Components.interfaces; var tempScope = {}; Components.utils.import("resource://gre/modules/FileUtils.jsm", tempScope); diff --git a/devtools/client/styleeditor/test/browser_styleeditor_sourcemap_watching.js b/devtools/client/styleeditor/test/browser_styleeditor_sourcemap_watching.js index f0eebb8f3fb6..c2b8344316b9 100644 --- a/devtools/client/styleeditor/test/browser_styleeditor_sourcemap_watching.js +++ b/devtools/client/styleeditor/test/browser_styleeditor_sourcemap_watching.js @@ -19,8 +19,8 @@ const TRANSITIONS_PREF = "devtools.styleeditor.transitions"; const CSS_TEXT = "* { color: blue }"; -var Cc = Components.classes; -var Ci = Components.interfaces; +const Cc = Components.classes; +const Ci = Components.interfaces; var tempScope = {}; Components.utils.import("resource://gre/modules/FileUtils.jsm", tempScope); diff --git a/devtools/client/styleinspector/test/head.js b/devtools/client/styleinspector/test/head.js index e3a8b15a5058..79d9a8d4fe00 100644 --- a/devtools/client/styleinspector/test/head.js +++ b/devtools/client/styleinspector/test/head.js @@ -4,7 +4,7 @@ "use strict"; -var Cu = Components.utils; +const Cu = Components.utils; var {gDevTools} = Cu.import("resource:///modules/devtools/client/framework/gDevTools.jsm", {}); var {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); var {TargetFactory} = require("devtools/client/framework/target"); diff --git a/devtools/client/styleinspector/test/unit/test_escapeCSSComment.js b/devtools/client/styleinspector/test/unit/test_escapeCSSComment.js index 3c99e0681f42..fa23cfc46e29 100644 --- a/devtools/client/styleinspector/test/unit/test_escapeCSSComment.js +++ b/devtools/client/styleinspector/test/unit/test_escapeCSSComment.js @@ -5,7 +5,7 @@ "use strict"; -var Cu = Components.utils; +const Cu = Components.utils; Cu.import("resource://gre/modules/devtools/Loader.jsm"); const {escapeCSSComment, _unescapeCSSComment} = devtools.require("devtools/client/styleinspector/css-parsing-utils"); diff --git a/devtools/client/styleinspector/test/unit/test_parseDeclarations.js b/devtools/client/styleinspector/test/unit/test_parseDeclarations.js index 60b9783688a6..0512b008ed2f 100644 --- a/devtools/client/styleinspector/test/unit/test_parseDeclarations.js +++ b/devtools/client/styleinspector/test/unit/test_parseDeclarations.js @@ -5,7 +5,7 @@ "use strict"; -var Cu = Components.utils; +const Cu = Components.utils; const {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); const {parseDeclarations, _parseCommentDeclarations} = require("devtools/client/styleinspector/css-parsing-utils"); diff --git a/devtools/client/styleinspector/test/unit/test_parsePseudoClassesAndAttributes.js b/devtools/client/styleinspector/test/unit/test_parsePseudoClassesAndAttributes.js index e9aae4d90bde..882bd7b14f24 100644 --- a/devtools/client/styleinspector/test/unit/test_parsePseudoClassesAndAttributes.js +++ b/devtools/client/styleinspector/test/unit/test_parsePseudoClassesAndAttributes.js @@ -5,7 +5,7 @@ "use strict"; -var Cu = Components.utils; +const Cu = Components.utils; const {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); const { parsePseudoClassesAndAttributes, diff --git a/devtools/client/styleinspector/test/unit/test_parseSingleValue.js b/devtools/client/styleinspector/test/unit/test_parseSingleValue.js index 8621591d2a84..7f46f9d38a6e 100644 --- a/devtools/client/styleinspector/test/unit/test_parseSingleValue.js +++ b/devtools/client/styleinspector/test/unit/test_parseSingleValue.js @@ -5,7 +5,7 @@ "use strict"; -var Cu = Components.utils; +const Cu = Components.utils; const {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); const {parseSingleValue} = require("devtools/client/styleinspector/css-parsing-utils"); diff --git a/devtools/client/styleinspector/test/unit/test_rewriteDeclarations.js b/devtools/client/styleinspector/test/unit/test_rewriteDeclarations.js index a5d3ea4883fb..55a62b7a9ad8 100644 --- a/devtools/client/styleinspector/test/unit/test_rewriteDeclarations.js +++ b/devtools/client/styleinspector/test/unit/test_rewriteDeclarations.js @@ -5,7 +5,7 @@ "use strict"; -var Cu = Components.utils; +const Cu = Components.utils; Cu.import("resource://gre/modules/devtools/Loader.jsm"); const {parseDeclarations, RuleRewriter} = devtools.require("devtools/client/styleinspector/css-parsing-utils"); diff --git a/devtools/client/webaudioeditor/includes.js b/devtools/client/webaudioeditor/includes.js index 65f13a34e13b..5f0eb485e72b 100644 --- a/devtools/client/webaudioeditor/includes.js +++ b/devtools/client/webaudioeditor/includes.js @@ -3,7 +3,7 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; -var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); diff --git a/devtools/client/webaudioeditor/test/head.js b/devtools/client/webaudioeditor/test/head.js index c0de74d43a42..ad46908db02b 100644 --- a/devtools/client/webaudioeditor/test/head.js +++ b/devtools/client/webaudioeditor/test/head.js @@ -2,7 +2,7 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; -var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; var { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); diff --git a/devtools/client/webconsole/test/browser_webconsole_netlogging_reset_filter.js b/devtools/client/webconsole/test/browser_webconsole_netlogging_reset_filter.js index 0661d8866c17..2a40ee2fdeb4 100644 --- a/devtools/client/webconsole/test/browser_webconsole_netlogging_reset_filter.js +++ b/devtools/client/webconsole/test/browser_webconsole_netlogging_reset_filter.js @@ -12,9 +12,9 @@ const TEST_FILE_URI = "test-network.html"; const TEST_URI = "data:text/html;charset=utf8,

test file URI"; -var hud; +let hud; -var test = asyncTest(function* () { +let test = asyncTest(function* () { let requests = []; let { browser } = yield loadTab(TEST_URI); diff --git a/devtools/client/webide/content/addons.js b/devtools/client/webide/content/addons.js index 552111d13c88..dd6b82a60091 100644 --- a/devtools/client/webide/content/addons.js +++ b/devtools/client/webide/content/addons.js @@ -2,7 +2,7 @@ * 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 Cu = Components.utils; +const Cu = Components.utils; const {Services} = Cu.import("resource://gre/modules/Services.jsm"); const {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); const {GetAvailableAddons, ForgetAddonsList} = require("devtools/client/webide/modules/addons"); diff --git a/devtools/client/webide/content/details.js b/devtools/client/webide/content/details.js index 149c7247e1fe..9a10f41624b2 100644 --- a/devtools/client/webide/content/details.js +++ b/devtools/client/webide/content/details.js @@ -2,7 +2,7 @@ * 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 Cu = Components.utils; +const Cu = Components.utils; Cu.import("resource:///modules/devtools/client/framework/gDevTools.jsm"); const {Services} = Cu.import("resource://gre/modules/Services.jsm"); const {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); diff --git a/devtools/client/webide/content/devicepreferences.js b/devtools/client/webide/content/devicepreferences.js index 2e203bd90198..b2dd22d73995 100644 --- a/devtools/client/webide/content/devicepreferences.js +++ b/devtools/client/webide/content/devicepreferences.js @@ -2,7 +2,7 @@ * 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 Cu = Components.utils; +const Cu = Components.utils; const {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); const {AppManager} = require("devtools/client/webide/modules/app-manager"); const {Connection} = require("devtools/shared/client/connection-manager"); diff --git a/devtools/client/webide/content/devicesettings.js b/devtools/client/webide/content/devicesettings.js index 14d47a95b544..c81624b08354 100644 --- a/devtools/client/webide/content/devicesettings.js +++ b/devtools/client/webide/content/devicesettings.js @@ -2,7 +2,7 @@ * 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 Cu = Components.utils; +const Cu = Components.utils; const {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); const {AppManager} = require("devtools/client/webide/modules/app-manager"); const {Connection} = require("devtools/shared/client/connection-manager"); diff --git a/devtools/client/webide/content/logs.js b/devtools/client/webide/content/logs.js index ebe0782bf5e3..9045204c9295 100644 --- a/devtools/client/webide/content/logs.js +++ b/devtools/client/webide/content/logs.js @@ -2,7 +2,7 @@ * 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 Cu = Components.utils; +const Cu = Components.utils; Cu.import("resource:///modules/devtools/client/framework/gDevTools.jsm"); const {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); const {AppManager} = require("devtools/client/webide/modules/app-manager"); diff --git a/devtools/client/webide/content/monitor.js b/devtools/client/webide/content/monitor.js index 8f32ad0eef79..8fbcaaef8d36 100644 --- a/devtools/client/webide/content/monitor.js +++ b/devtools/client/webide/content/monitor.js @@ -2,7 +2,7 @@ * 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 Cu = Components.utils; +const Cu = Components.utils; Cu.import('resource:///modules/devtools/client/framework/gDevTools.jsm'); const {require} = Cu.import('resource://gre/modules/devtools/shared/Loader.jsm', {}); const {Services} = Cu.import('resource://gre/modules/Services.jsm'); diff --git a/devtools/client/webide/content/newapp.js b/devtools/client/webide/content/newapp.js index 6f5f56c77fc3..b63b65108374 100644 --- a/devtools/client/webide/content/newapp.js +++ b/devtools/client/webide/content/newapp.js @@ -2,9 +2,9 @@ * 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 Cc = Components.classes; -var Cu = Components.utils; -var Ci = Components.interfaces; +const Cc = Components.classes; +const Cu = Components.utils; +const Ci = Components.interfaces; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); diff --git a/devtools/client/webide/content/permissionstable.js b/devtools/client/webide/content/permissionstable.js index 3422df47d9c4..7b82fde2a4ba 100644 --- a/devtools/client/webide/content/permissionstable.js +++ b/devtools/client/webide/content/permissionstable.js @@ -2,7 +2,7 @@ * 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 Cu = Components.utils; +const Cu = Components.utils; const {Services} = Cu.import("resource://gre/modules/Services.jsm"); const {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); const {AppManager} = require("devtools/client/webide/modules/app-manager"); diff --git a/devtools/client/webide/content/prefs.js b/devtools/client/webide/content/prefs.js index 1137b11530fe..dca974f15f01 100644 --- a/devtools/client/webide/content/prefs.js +++ b/devtools/client/webide/content/prefs.js @@ -2,7 +2,7 @@ * 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 Cu = Components.utils; +const Cu = Components.utils; const {Services} = Cu.import("resource://gre/modules/Services.jsm"); window.addEventListener("load", function onLoad() { diff --git a/devtools/client/webide/content/project-listing.js b/devtools/client/webide/content/project-listing.js index f5241ae67338..bfaf3a7e8891 100644 --- a/devtools/client/webide/content/project-listing.js +++ b/devtools/client/webide/content/project-listing.js @@ -4,7 +4,7 @@ /* eslint-env browser */ -var Cu = Components.utils; +const Cu = Components.utils; const {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); const ProjectList = require("devtools/client/webide/modules/project-list"); diff --git a/devtools/client/webide/content/runtime-listing.js b/devtools/client/webide/content/runtime-listing.js index 9922791fa933..659faa09b3f2 100644 --- a/devtools/client/webide/content/runtime-listing.js +++ b/devtools/client/webide/content/runtime-listing.js @@ -2,7 +2,7 @@ * 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 Cu = Components.utils; +const Cu = Components.utils; const {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); const RuntimeList = require("devtools/client/webide/modules/runtime-list"); diff --git a/devtools/client/webide/content/runtimedetails.js b/devtools/client/webide/content/runtimedetails.js index c54b4c286423..73211932a175 100644 --- a/devtools/client/webide/content/runtimedetails.js +++ b/devtools/client/webide/content/runtimedetails.js @@ -2,7 +2,7 @@ * 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 Cu = Components.utils; +const Cu = Components.utils; const {Services} = Cu.import("resource://gre/modules/Services.jsm"); const {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); const {AppManager} = require("devtools/client/webide/modules/app-manager"); diff --git a/devtools/client/webide/content/simulator.js b/devtools/client/webide/content/simulator.js index 1e5708652e35..5e396954c38e 100644 --- a/devtools/client/webide/content/simulator.js +++ b/devtools/client/webide/content/simulator.js @@ -2,7 +2,7 @@ * 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 Cu = Components.utils; +const Cu = Components.utils; const { require } = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); const { GetDevices, GetDeviceString } = require("devtools/client/shared/devices"); diff --git a/devtools/client/webide/content/webide.js b/devtools/client/webide/content/webide.js index e5f9699c8685..4ef7cc3dd504 100644 --- a/devtools/client/webide/content/webide.js +++ b/devtools/client/webide/content/webide.js @@ -2,9 +2,9 @@ * 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 Cc = Components.classes; -var Cu = Components.utils; -var Ci = Components.interfaces; +const Cc = Components.classes; +const Cu = Components.utils; +const Ci = Components.interfaces; Cu.import("resource:///modules/devtools/client/framework/gDevTools.jsm"); Cu.import("resource://gre/modules/Task.jsm"); diff --git a/devtools/client/webide/content/wifi-auth.js b/devtools/client/webide/content/wifi-auth.js index ee35ee5f22fb..0341c2e8ee7a 100644 --- a/devtools/client/webide/content/wifi-auth.js +++ b/devtools/client/webide/content/wifi-auth.js @@ -4,7 +4,7 @@ "use strict"; -var Cu = Components.utils; +const Cu = Components.utils; const { Services } = Cu.import("resource://gre/modules/Services.jsm"); const { require } = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); diff --git a/devtools/client/webide/test/head.js b/devtools/client/webide/test/head.js index 662f905066aa..b44269893d0e 100644 --- a/devtools/client/webide/test/head.js +++ b/devtools/client/webide/test/head.js @@ -3,7 +3,7 @@ "use strict"; -var {utils: Cu, classes: Cc, interfaces: Ci} = Components; +const {utils: Cu, classes: Cc, interfaces: Ci} = Components; Cu.import('resource://gre/modules/Services.jsm'); Cu.import("resource://gre/modules/FileUtils.jsm"); diff --git a/devtools/server/actors/highlighters.js b/devtools/server/actors/highlighters.js index 00ffb51dde0f..aeb4bd18c590 100644 --- a/devtools/server/actors/highlighters.js +++ b/devtools/server/actors/highlighters.js @@ -79,7 +79,7 @@ exports.register = register; /** * The HighlighterActor class */ -var HighlighterActor = exports.HighlighterActor = protocol.ActorClass({ +let HighlighterActor = exports.HighlighterActor = protocol.ActorClass({ typeName: "highlighter", initialize: function(inspector, autohide) { @@ -408,7 +408,7 @@ var HighlighterActor = exports.HighlighterActor = protocol.ActorClass({ }) }); -var HighlighterFront = protocol.FrontClass(HighlighterActor, { +let HighlighterFront = protocol.FrontClass(HighlighterActor, { // Update the object given a form representation off the wire. form: function(json) { this.actorID = json.actor; @@ -421,7 +421,7 @@ var HighlighterFront = protocol.FrontClass(HighlighterActor, { * A generic highlighter actor class that instantiate a highlighter given its * type name and allows to show/hide it. */ -var CustomHighlighterActor = exports.CustomHighlighterActor = protocol.ActorClass({ +let CustomHighlighterActor = exports.CustomHighlighterActor = protocol.ActorClass({ typeName: "customhighlighter", /** @@ -527,7 +527,7 @@ var CustomHighlighterActor = exports.CustomHighlighterActor = protocol.ActorClas }) }); -var CustomHighlighterFront = protocol.FrontClass(CustomHighlighterActor, {}); +let CustomHighlighterFront = protocol.FrontClass(CustomHighlighterActor, {}); /** * The HighlighterEnvironment is an object that holds all the required data for diff --git a/devtools/server/actors/highlighters/css-transform.js b/devtools/server/actors/highlighters/css-transform.js index edd6cd27037d..f2569df6900f 100644 --- a/devtools/server/actors/highlighters/css-transform.js +++ b/devtools/server/actors/highlighters/css-transform.js @@ -15,7 +15,7 @@ const { setIgnoreLayoutChanges, // The minimum distance a line should be before it has an arrow marker-end const ARROW_LINE_MIN_DISTANCE = 10; -var MARKER_COUNTER = 1; +let MARKER_COUNTER = 1; /** * The CssTransformHighlighter is the class that draws an outline around a diff --git a/devtools/server/actors/highlighters/geometry-editor.js b/devtools/server/actors/highlighters/geometry-editor.js index 5a8138f6902d..4d50b16a0312 100644 --- a/devtools/server/actors/highlighters/geometry-editor.js +++ b/devtools/server/actors/highlighters/geometry-editor.js @@ -19,7 +19,7 @@ const GEOMETRY_LABEL_SIZE = 6; * Element geometry properties helper that gives names of position and size * properties. */ -var GeoProp = { +let GeoProp = { SIDES: ["top", "right", "bottom", "left"], SIZES: ["width", "height"], diff --git a/devtools/server/actors/highlighters/utils/markup.js b/devtools/server/actors/highlighters/utils/markup.js index a44dab53d185..a8d0e91a04ff 100644 --- a/devtools/server/actors/highlighters/utils/markup.js +++ b/devtools/server/actors/highlighters/utils/markup.js @@ -50,7 +50,7 @@ exports.isXUL = isXUL; /** * Inject a helper stylesheet in the window. */ -var installedHelperSheets = new WeakMap(); +let installedHelperSheets = new WeakMap(); function installHelperSheet(win, source, type = "agent") { if (installedHelperSheets.has(win.document)) { diff --git a/devtools/server/actors/memprof.js b/devtools/server/actors/memprof.js index 1686111c72d5..95195712cb8b 100644 --- a/devtools/server/actors/memprof.js +++ b/devtools/server/actors/memprof.js @@ -5,12 +5,12 @@ "use strict"; const { Cc, Ci, Cu } = require("chrome"); -var protocol = require("devtools/server/protocol"); -var { method, RetVal, Arg, types } = protocol; +let protocol = require("devtools/server/protocol"); +let { method, RetVal, Arg, types } = protocol; const { reportException } = require("devtools/shared/DevToolsUtils"); loader.lazyRequireGetter(this, "events", "sdk/event/core"); -var MemprofActor = protocol.ActorClass({ +let MemprofActor = protocol.ActorClass({ typeName: "memprof", initialize: function(conn) { diff --git a/devtools/server/tests/browser/head.js b/devtools/server/tests/browser/head.js index b3144b4af54f..dd6fda866801 100644 --- a/devtools/server/tests/browser/head.js +++ b/devtools/server/tests/browser/head.js @@ -2,9 +2,9 @@ * 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 Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; Cu.import("resource://gre/modules/Services.jsm"); const {console} = Cu.import("resource://gre/modules/devtools/shared/Console.jsm", {}); diff --git a/devtools/server/tests/mochitest/memprof-helpers.js b/devtools/server/tests/mochitest/memprof-helpers.js index 07e4bc0d1faf..2d11f26b2791 100644 --- a/devtools/server/tests/mochitest/memprof-helpers.js +++ b/devtools/server/tests/mochitest/memprof-helpers.js @@ -1,8 +1,8 @@ -var Cu = Components.utils; -var Cc = Components.classes; -var Ci = Components.interfaces; +let Cu = Components.utils; +let Cc = Components.classes; +let Ci = Components.interfaces; -var { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); +let { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); // Always log packets when running tests. Services.prefs.setBoolPref("devtools.debugger.log", true); @@ -10,13 +10,13 @@ SimpleTest.registerCleanupFunction(function() { Services.prefs.clearUserPref("devtools.debugger.log"); }); -var { Task } = Cu.import("resource://gre/modules/Task.jsm", {}); -var { require } = +let { Task } = Cu.import("resource://gre/modules/Task.jsm", {}); +let { require } = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); -var { DebuggerClient } = require("devtools/shared/client/main"); -var { DebuggerServer } = require("devtools/server/main"); -var { MemprofFront } = require("devtools/server/actors/memprof"); +let { DebuggerClient } = require("devtools/shared/client/main"); +let { DebuggerServer } = require("devtools/server/main"); +let { MemprofFront } = require("devtools/server/actors/memprof"); function startServerAndGetSelectedTabMemprof() { DebuggerServer.init(); diff --git a/devtools/server/tests/unit/head_dbg.js b/devtools/server/tests/unit/head_dbg.js index ee24ba7b42a5..f83e4a8395d2 100644 --- a/devtools/server/tests/unit/head_dbg.js +++ b/devtools/server/tests/unit/head_dbg.js @@ -2,11 +2,11 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; -var Cr = Components.results; -var CC = Components.Constructor; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; +const CC = Components.Constructor; const { require, loader } = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); const { worker } = Cu.import("resource://gre/modules/devtools/shared/worker-loader.js", {}) diff --git a/devtools/shared/acorn/tests/unit/head_acorn.js b/devtools/shared/acorn/tests/unit/head_acorn.js index 2ddf6f91d477..2fbd4b345e1b 100644 --- a/devtools/shared/acorn/tests/unit/head_acorn.js +++ b/devtools/shared/acorn/tests/unit/head_acorn.js @@ -1,5 +1,5 @@ "use strict"; -var { classes: Cc, interfaces: Ci, utils: Cu } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; const { require } = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); diff --git a/devtools/shared/apps/tests/debugger-protocol-helper.js b/devtools/shared/apps/tests/debugger-protocol-helper.js index 75fec9f79205..2a3888452873 100644 --- a/devtools/shared/apps/tests/debugger-protocol-helper.js +++ b/devtools/shared/apps/tests/debugger-protocol-helper.js @@ -1,9 +1,9 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; const { require } = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); const { DebuggerClient } = require("devtools/shared/client/main"); diff --git a/devtools/shared/apps/tests/unit/head_apps.js b/devtools/shared/apps/tests/unit/head_apps.js index 781e217be04b..3bdd6d629242 100644 --- a/devtools/shared/apps/tests/unit/head_apps.js +++ b/devtools/shared/apps/tests/unit/head_apps.js @@ -1,11 +1,11 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; -var Cr = Components.results; -var CC = Components.Constructor; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; +const CC = Components.Constructor; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); diff --git a/devtools/shared/discovery/tests/unit/test_discovery.js b/devtools/shared/discovery/tests/unit/test_discovery.js index ee9ca534b1fe..d2fdc2758e79 100644 --- a/devtools/shared/discovery/tests/unit/test_discovery.js +++ b/devtools/shared/discovery/tests/unit/test_discovery.js @@ -3,7 +3,7 @@ "use strict"; -var Cu = Components.utils; +const Cu = Components.utils; const { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); Services.prefs.setBoolPref("devtools.discovery.log", true); diff --git a/devtools/shared/heapsnapshot/tests/unit/head_heapsnapshot.js b/devtools/shared/heapsnapshot/tests/unit/head_heapsnapshot.js index 0e17883042b3..9e3a49d8d740 100644 --- a/devtools/shared/heapsnapshot/tests/unit/head_heapsnapshot.js +++ b/devtools/shared/heapsnapshot/tests/unit/head_heapsnapshot.js @@ -3,11 +3,11 @@ "use strict"; -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; -var Cr = Components.results; -var CC = Components.Constructor; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; +const CC = Components.Constructor; const { require } = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); const { Match } = Cu.import("resource://test/Match.jsm", {}); diff --git a/devtools/shared/jsbeautify/tests/unit/head_jsbeautify.js b/devtools/shared/jsbeautify/tests/unit/head_jsbeautify.js index a2c8708dba23..c1ffb82510ac 100644 --- a/devtools/shared/jsbeautify/tests/unit/head_jsbeautify.js +++ b/devtools/shared/jsbeautify/tests/unit/head_jsbeautify.js @@ -4,10 +4,10 @@ "use strict"; -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; -var Cr = Components.results; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; const { require } = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); diff --git a/devtools/shared/performance/test/head.js b/devtools/shared/performance/test/head.js index 2e24fe9f883a..6d0fc3b72829 100644 --- a/devtools/shared/performance/test/head.js +++ b/devtools/shared/performance/test/head.js @@ -2,6 +2,6 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; -var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; var { require } = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); diff --git a/devtools/shared/pretty-fast/tests/unit/head_pretty-fast.js b/devtools/shared/pretty-fast/tests/unit/head_pretty-fast.js index 9d515e816213..0224072c6611 100644 --- a/devtools/shared/pretty-fast/tests/unit/head_pretty-fast.js +++ b/devtools/shared/pretty-fast/tests/unit/head_pretty-fast.js @@ -1,8 +1,8 @@ "use strict"; -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; -var Cr = Components.results; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; const { require } = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); diff --git a/devtools/shared/qrcode/tests/unit/test_encode.js b/devtools/shared/qrcode/tests/unit/test_encode.js index 4dea334be074..cf7e0901696d 100644 --- a/devtools/shared/qrcode/tests/unit/test_encode.js +++ b/devtools/shared/qrcode/tests/unit/test_encode.js @@ -6,7 +6,7 @@ * Test encoding a simple message. */ -var { utils: Cu } = Components; +const { utils: Cu } = Components; const { require } = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); const QR = require("devtools/shared/qrcode/index"); diff --git a/devtools/shared/security/tests/unit/head_dbg.js b/devtools/shared/security/tests/unit/head_dbg.js index 7e5ed488bfa9..00c1ab5ae2e2 100644 --- a/devtools/shared/security/tests/unit/head_dbg.js +++ b/devtools/shared/security/tests/unit/head_dbg.js @@ -2,11 +2,11 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; -var Cr = Components.results; -var CC = Components.Constructor; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; +const CC = Components.Constructor; const { require } = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); diff --git a/devtools/shared/shared/tests/unit/test_indentation.js b/devtools/shared/shared/tests/unit/test_indentation.js index 15ea9e62de15..cacee6ab11b1 100644 --- a/devtools/shared/shared/tests/unit/test_indentation.js +++ b/devtools/shared/shared/tests/unit/test_indentation.js @@ -3,7 +3,7 @@ "use strict"; -var Cu = Components.utils; +const Cu = Components.utils; const {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm"); const Services = require("Services"); const { diff --git a/devtools/shared/shims/dbg-client.jsm b/devtools/shared/shims/dbg-client.jsm index bb93630419af..6f3c66d6fd8e 100644 --- a/devtools/shared/shims/dbg-client.jsm +++ b/devtools/shared/shims/dbg-client.jsm @@ -31,7 +31,7 @@ this.EXPORTED_SYMBOLS = ["DebuggerTransport", "EnvironmentClient", "ObjectClient"]; -var client = require("devtools/shared/client/main"); +let client = require("devtools/shared/client/main"); this.DebuggerClient = client.DebuggerClient; this.RootClient = client.RootClient; diff --git a/devtools/shared/sourcemap/tests/unit/head_sourcemap.js b/devtools/shared/sourcemap/tests/unit/head_sourcemap.js index 12d4c078ebc8..f85497a98a90 100644 --- a/devtools/shared/sourcemap/tests/unit/head_sourcemap.js +++ b/devtools/shared/sourcemap/tests/unit/head_sourcemap.js @@ -2,10 +2,10 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; -var Cr = Components.results; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; function doesNotThrow(f) { try { diff --git a/devtools/shared/tern/tests/unit/head_tern.js b/devtools/shared/tern/tests/unit/head_tern.js index acccc25e754f..57c2c1ad3210 100644 --- a/devtools/shared/tern/tests/unit/head_tern.js +++ b/devtools/shared/tern/tests/unit/head_tern.js @@ -1,3 +1,3 @@ "use strict"; -var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; const { require } = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); diff --git a/devtools/shared/tests/unit/head_devtools.js b/devtools/shared/tests/unit/head_devtools.js index 219c1c17c3bf..d89b4f1da556 100644 --- a/devtools/shared/tests/unit/head_devtools.js +++ b/devtools/shared/tests/unit/head_devtools.js @@ -1,8 +1,8 @@ "use strict"; -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; -var Cr = Components.results; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; var {require} = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm"); const DevToolsUtils = require("devtools/shared/DevToolsUtils"); diff --git a/devtools/shared/transport/tests/unit/head_dbg.js b/devtools/shared/transport/tests/unit/head_dbg.js index edabc9430654..c111b6b43095 100644 --- a/devtools/shared/transport/tests/unit/head_dbg.js +++ b/devtools/shared/transport/tests/unit/head_dbg.js @@ -2,11 +2,11 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; -var Cr = Components.results; -var CC = Components.Constructor; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; +const CC = Components.Constructor; const { require } = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); diff --git a/devtools/shared/webconsole/test/common.js b/devtools/shared/webconsole/test/common.js index 32e337e6ede6..f3629db1f540 100644 --- a/devtools/shared/webconsole/test/common.js +++ b/devtools/shared/webconsole/test/common.js @@ -3,7 +3,7 @@ "use strict"; -var {classes: Cc, interfaces: Ci, utils: Cu} = Components; +const {classes: Cc, interfaces: Ci, utils: Cu} = Components; const XHTML_NS = "http://www.w3.org/1999/xhtml"; diff --git a/devtools/shared/webconsole/test/unit/test_network_helper.js b/devtools/shared/webconsole/test/unit/test_network_helper.js index 2dbbf7d72804..b07a913b8419 100644 --- a/devtools/shared/webconsole/test/unit/test_network_helper.js +++ b/devtools/shared/webconsole/test/unit/test_network_helper.js @@ -2,7 +2,7 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; -var Cu = Components.utils; +const Cu = Components.utils; const { require } = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {}); Object.defineProperty(this, "NetworkHelper", { diff --git a/devtools/shared/webconsole/test/unit/test_security-info-certificate.js b/devtools/shared/webconsole/test/unit/test_security-info-certificate.js index aef39e12b5d4..12f11d50da72 100644 --- a/devtools/shared/webconsole/test/unit/test_security-info-certificate.js +++ b/devtools/shared/webconsole/test/unit/test_security-info-certificate.js @@ -17,7 +17,7 @@ Object.defineProperty(this, "NetworkHelper", { enumerable: true }); -var Ci = Components.interfaces; +const Ci = Components.interfaces; const DUMMY_CERT = { commonName: "cn", organization: "o", diff --git a/devtools/shared/webconsole/test/unit/test_security-info-parser.js b/devtools/shared/webconsole/test/unit/test_security-info-parser.js index dd32949e9573..57bd41154ff7 100644 --- a/devtools/shared/webconsole/test/unit/test_security-info-parser.js +++ b/devtools/shared/webconsole/test/unit/test_security-info-parser.js @@ -17,7 +17,7 @@ Object.defineProperty(this, "NetworkHelper", { enumerable: true }); -var Ci = Components.interfaces; +const Ci = Components.interfaces; const wpl = Ci.nsIWebProgressListener; const MockCertificate = { commonName: "cn", diff --git a/devtools/shared/webconsole/test/unit/test_security-info-protocol-version.js b/devtools/shared/webconsole/test/unit/test_security-info-protocol-version.js index 7be43815c301..557e13b8038d 100644 --- a/devtools/shared/webconsole/test/unit/test_security-info-protocol-version.js +++ b/devtools/shared/webconsole/test/unit/test_security-info-protocol-version.js @@ -17,7 +17,7 @@ Object.defineProperty(this, "NetworkHelper", { enumerable: true }); -var Ci = Components.interfaces; +const Ci = Components.interfaces; const TEST_CASES = [ { description: "TLS_VERSION_1", diff --git a/devtools/shared/webconsole/test/unit/test_security-info-state.js b/devtools/shared/webconsole/test/unit/test_security-info-state.js index e02824ef771f..898b9b8d3332 100644 --- a/devtools/shared/webconsole/test/unit/test_security-info-state.js +++ b/devtools/shared/webconsole/test/unit/test_security-info-state.js @@ -18,7 +18,7 @@ Object.defineProperty(this, "NetworkHelper", { enumerable: true }); -var Ci = Components.interfaces; +const Ci = Components.interfaces; const wpl = Ci.nsIWebProgressListener; const MockSecurityInfo = { QueryInterface: XPCOMUtils.generateQI([Ci.nsITransportSecurityInfo, diff --git a/devtools/shared/webconsole/test/unit/test_security-info-static-hpkp.js b/devtools/shared/webconsole/test/unit/test_security-info-static-hpkp.js index e16665a67019..b07fdc2538ce 100644 --- a/devtools/shared/webconsole/test/unit/test_security-info-static-hpkp.js +++ b/devtools/shared/webconsole/test/unit/test_security-info-static-hpkp.js @@ -18,7 +18,7 @@ Object.defineProperty(this, "NetworkHelper", { enumerable: true }); -var Ci = Components.interfaces; +const Ci = Components.interfaces; const wpl = Ci.nsIWebProgressListener; const MockSecurityInfo = { diff --git a/devtools/shared/webconsole/test/unit/test_security-info-weakness-reasons.js b/devtools/shared/webconsole/test/unit/test_security-info-weakness-reasons.js index f440eb217544..ce84937663e8 100644 --- a/devtools/shared/webconsole/test/unit/test_security-info-weakness-reasons.js +++ b/devtools/shared/webconsole/test/unit/test_security-info-weakness-reasons.js @@ -17,7 +17,7 @@ Object.defineProperty(this, "NetworkHelper", { enumerable: true }); -var Ci = Components.interfaces; +const Ci = Components.interfaces; const wpl = Ci.nsIWebProgressListener; const TEST_CASES = [ { diff --git a/docshell/test/browser/browser_loadURI.js b/docshell/test/browser/browser_loadURI.js index 4d85ff6bc717..ac04fa591740 100644 --- a/docshell/test/browser/browser_loadURI.js +++ b/docshell/test/browser/browser_loadURI.js @@ -1,8 +1,8 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ -var Cc = Components.classes; -var Ci = Components.interfaces; +const Cc = Components.classes; +const Ci = Components.interfaces; const gPostData = "postdata=true"; diff --git a/docshell/test/browser/frame-head.js b/docshell/test/browser/frame-head.js index 5cb3b1513300..1b7077eb0993 100644 --- a/docshell/test/browser/frame-head.js +++ b/docshell/test/browser/frame-head.js @@ -4,7 +4,7 @@ // Functions that are automatically loaded as frame scripts for // timeline tests. -var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; var { Task } = Cu.import("resource://gre/modules/Task.jsm", {}); var { Promise } = Cu.import('resource://gre/modules/Promise.jsm', {}); diff --git a/docshell/test/unit/head_docshell.js b/docshell/test/unit/head_docshell.js index a5c7546c04e6..643f1fccdc65 100644 --- a/docshell/test/unit/head_docshell.js +++ b/docshell/test/unit/head_docshell.js @@ -2,9 +2,9 @@ * 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 Cc = Components.classes; -var Ci = Components.interfaces; -var Cr = Components.results; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cr = Components.results; var dirSvc = Cc["@mozilla.org/file/directory_service;1"]. getService(Ci.nsIProperties); diff --git a/docshell/test/unit/test_nsDefaultURIFixup_search.js b/docshell/test/unit/test_nsDefaultURIFixup_search.js index c00b6a85f595..acf35ad94347 100644 --- a/docshell/test/unit/test_nsDefaultURIFixup_search.js +++ b/docshell/test/unit/test_nsDefaultURIFixup_search.js @@ -1,4 +1,4 @@ -var urifixup = Cc["@mozilla.org/docshell/urifixup;1"]. +let urifixup = Cc["@mozilla.org/docshell/urifixup;1"]. getService(Ci.nsIURIFixup); Components.utils.import("resource://gre/modules/Services.jsm"); Components.utils.import("resource://gre/modules/AppConstants.jsm"); @@ -10,10 +10,10 @@ const kSearchEngineURL = "http://www.example.org/?search={searchTerms}"; Services.search.addEngineWithDetails(kSearchEngineID, "", "", "", "get", kSearchEngineURL); -var oldDefaultEngine = Services.search.defaultEngine; +let oldDefaultEngine = Services.search.defaultEngine; Services.search.defaultEngine = Services.search.getEngineByName(kSearchEngineID); -var selectedName = Services.search.defaultEngine.name; +let selectedName = Services.search.defaultEngine.name; do_check_eq(selectedName, kSearchEngineID); do_register_cleanup(function() { @@ -27,9 +27,9 @@ do_register_cleanup(function() { Services.prefs.clearUserPref("keyword.enabled"); }); -var isWin = AppConstants.platform == "win"; +let isWin = AppConstants.platform == "win"; -var data = [ +let data = [ { // Valid should not be changed. wrong: 'https://example.com/this/is/a/test.html', @@ -90,7 +90,7 @@ var data = [ }, ]; -var extProtocolSvc = Cc["@mozilla.org/uriloader/external-protocol-service;1"] +let extProtocolSvc = Cc["@mozilla.org/uriloader/external-protocol-service;1"] .getService(Ci.nsIExternalProtocolService); if (extProtocolSvc && extProtocolSvc.externalProtocolHandlerExists("mailto")) { @@ -104,7 +104,7 @@ function run_test() { run_next_test(); } -var len = data.length; +let len = data.length; // Make sure we fix what needs fixing add_task(function test_fix_unknown_schemes() { for (let i = 0; i < len; ++i) { diff --git a/docshell/test/unit_ipc/test_pb_notification_ipc.js b/docshell/test/unit_ipc/test_pb_notification_ipc.js index 1517a479fd89..06a0fc7b1f22 100644 --- a/docshell/test/unit_ipc/test_pb_notification_ipc.js +++ b/docshell/test/unit_ipc/test_pb_notification_ipc.js @@ -1,5 +1,5 @@ -var Cc = Components.classes; -var Ci = Components.interfaces; +const Cc = Components.classes; +const Ci = Components.interfaces; function run_test() { var notifications = 0; diff --git a/dom/activities/tests/mochi/common.js b/dom/activities/tests/mochi/common.js index 9f32d0e6bd62..71d167d690d3 100644 --- a/dom/activities/tests/mochi/common.js +++ b/dom/activities/tests/mochi/common.js @@ -1,4 +1,4 @@ -var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; const ACTIVITY_GLUE_CID = Components.ID("{f4cfbe10-a106-4cd1-b04e-0d2a6aac138b}"); const SYS_MSG_GLUE_CID = Components.ID("{b0b6b9af-bc4e-4200-bffe-fb7691065ec9}"); diff --git a/dom/alarm/test/system_message_chrome_script.js b/dom/alarm/test/system_message_chrome_script.js index b00d744ac14d..4d6358f517e9 100644 --- a/dom/alarm/test/system_message_chrome_script.js +++ b/dom/alarm/test/system_message_chrome_script.js @@ -3,7 +3,7 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ 'use strict'; -var { classes: Cc, interfaces: Ci } = Components; +const { classes: Cc, interfaces: Ci } = Components; const systemMessenger = Cc["@mozilla.org/system-message-internal;1"] .getService(Ci.nsISystemMessagesInternal); diff --git a/dom/apps/tests/chromeAddCert.js b/dom/apps/tests/chromeAddCert.js index f01f49b62c9c..e555fb09b614 100644 --- a/dom/apps/tests/chromeAddCert.js +++ b/dom/apps/tests/chromeAddCert.js @@ -1,6 +1,6 @@ -var Ci = Components.interfaces; -var Cc = Components.classes; -var Cu = Components.utils; +const Ci = Components.interfaces; +const Cc = Components.classes; +const Cu = Components.utils; Cu.import("resource://gre/modules/StoreTrustAnchor.jsm"); diff --git a/dom/apps/tests/test_operator_app_install.js b/dom/apps/tests/test_operator_app_install.js index 64367ff985d2..9f81c44e73c7 100644 --- a/dom/apps/tests/test_operator_app_install.js +++ b/dom/apps/tests/test_operator_app_install.js @@ -1,8 +1,8 @@ "use strict"; -var Cu = Components.utils; -var Cc = Components.classes; -var Ci = Components.interfaces; +const Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; Cu.import("resource://gre/modules/OperatorApps.jsm"); Cu.import("resource://gre/modules/FileUtils.jsm"); diff --git a/dom/apps/tests/unit/head.js b/dom/apps/tests/unit/head.js index 1e4749ec5162..1c690c6afe16 100644 --- a/dom/apps/tests/unit/head.js +++ b/dom/apps/tests/unit/head.js @@ -1,4 +1,4 @@ -var {classes: Cc, interfaces: Ci, utils: Cu} = Components; +const {classes: Cc, interfaces: Ci, utils: Cu} = Components; Cu.import("resource:///modules/Services.jsm"); var dom_mozApps_debug = Services.prefs.getBoolPref("dom.mozApps.debug"); Services.prefs.setBoolPref("dom.mozApps.debug", true); diff --git a/dom/base/test/browser_state_notifications.js b/dom/base/test/browser_state_notifications.js index 3279acb39a56..b66086ae7ad5 100644 --- a/dom/base/test/browser_state_notifications.js +++ b/dom/base/test/browser_state_notifications.js @@ -4,7 +4,7 @@ "use strict"; -var { interfaces: Ci, classes: Cc, utils: Cu } = Components; +const { interfaces: Ci, classes: Cc, utils: Cu } = Components; const { addObserver, removeObserver } = Cc["@mozilla.org/observer-service;1"]. getService(Ci.nsIObserverService); const { openWindow } = Cc["@mozilla.org/embedcomp/window-watcher;1"]. diff --git a/dom/base/test/bug403852_fileOpener.js b/dom/base/test/bug403852_fileOpener.js index e8de8b5996e0..f48c9c7152c1 100644 --- a/dom/base/test/bug403852_fileOpener.js +++ b/dom/base/test/bug403852_fileOpener.js @@ -1,4 +1,4 @@ -var { classes: Cc, interfaces: Ci, utils: Cu } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; Cu.importGlobalProperties(["File"]); var testFile = Cc["@mozilla.org/file/directory_service;1"] diff --git a/dom/base/test/chrome/cpows_child.js b/dom/base/test/chrome/cpows_child.js index ff94f771f046..ec82edeef172 100644 --- a/dom/base/test/chrome/cpows_child.js +++ b/dom/base/test/chrome/cpows_child.js @@ -1,6 +1,6 @@ dump('loaded child cpow test\n'); -var Cu = Components.utils; +const Cu = Components.utils; (function start() { [is_remote] = sendRpcMessage("cpows:is_remote"); diff --git a/dom/base/test/chrome/test_domparsing.xul b/dom/base/test/chrome/test_domparsing.xul index c2a10710d0c3..f55fbc21a177 100644 --- a/dom/base/test/chrome/test_domparsing.xul +++ b/dom/base/test/chrome/test_domparsing.xul @@ -16,8 +16,8 @@ "use strict"; /** Test for Bug 816410 **/ -var Cc = Components.classes; -var Ci = Components.interfaces; +const Cc = Components.classes; +const Ci = Components.interfaces; function throws(a, type, message) { for (let fn of Array.isArray(a) ? a : [a]) { diff --git a/dom/base/test/chrome/test_fileconstructor_tempfile.xul b/dom/base/test/chrome/test_fileconstructor_tempfile.xul index 1f59b35e1734..4671af65d62c 100644 --- a/dom/base/test/chrome/test_fileconstructor_tempfile.xul +++ b/dom/base/test/chrome/test_fileconstructor_tempfile.xul @@ -32,9 +32,9 @@ the underlying file is removed when the DOMFile is gc'ed. SimpleTest.waitForExplicitFinish(); -var Ci = Components.interfaces; -var Cc = Components.classes; +const Ci = Components.interfaces; +const Cc = Components.classes; var geolocation = Cc["@mozilla.org/geolocation;1"].getService(Ci.nsISupports); geolocation.getCurrentPosition(done, error); diff --git a/dom/tests/mochitest/webapps/head.js b/dom/tests/mochitest/webapps/head.js index 8d5e9c042ff3..f34f75647156 100644 --- a/dom/tests/mochitest/webapps/head.js +++ b/dom/tests/mochitest/webapps/head.js @@ -1,7 +1,7 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ -var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); diff --git a/dom/tests/unit/test_geolocation_position_unavailable.js b/dom/tests/unit/test_geolocation_position_unavailable.js index 4a09d97989a1..77c1d4717202 100644 --- a/dom/tests/unit/test_geolocation_position_unavailable.js +++ b/dom/tests/unit/test_geolocation_position_unavailable.js @@ -1,7 +1,7 @@ -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; -var Cr = Components.results; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; function successCallback() { diff --git a/dom/tests/unit/test_geolocation_position_unavailable_wrap.js b/dom/tests/unit/test_geolocation_position_unavailable_wrap.js index 6bd5cc48c880..585c7511a791 100644 --- a/dom/tests/unit/test_geolocation_position_unavailable_wrap.js +++ b/dom/tests/unit/test_geolocation_position_unavailable_wrap.js @@ -1,6 +1,6 @@ -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; function run_test() { diff --git a/dom/tests/unit/test_geolocation_provider.js b/dom/tests/unit/test_geolocation_provider.js index 06451b6b9895..34d7803b0b39 100644 --- a/dom/tests/unit/test_geolocation_provider.js +++ b/dom/tests/unit/test_geolocation_provider.js @@ -1,7 +1,7 @@ -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; -var Cr = Components.results; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; Cu.import("resource://testing-common/httpd.js"); diff --git a/dom/tests/unit/test_geolocation_provider_timeout.js b/dom/tests/unit/test_geolocation_provider_timeout.js index d9078e5387fe..da5091e49a97 100644 --- a/dom/tests/unit/test_geolocation_provider_timeout.js +++ b/dom/tests/unit/test_geolocation_provider_timeout.js @@ -1,6 +1,6 @@ -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; Cu.import("resource://testing-common/httpd.js"); diff --git a/dom/tests/unit/test_geolocation_reset_accuracy.js b/dom/tests/unit/test_geolocation_reset_accuracy.js index 5d71b5930f8e..92f7949eeea8 100644 --- a/dom/tests/unit/test_geolocation_reset_accuracy.js +++ b/dom/tests/unit/test_geolocation_reset_accuracy.js @@ -1,5 +1,5 @@ -var Cc = Components.classes; -var Ci = Components.interfaces; +const Cc = Components.classes; +const Ci = Components.interfaces; const providerCID = Components.ID("{14aa4b81-e266-45cb-88f8-89595dece114}"); const providerContract = "@mozilla.org/geolocation/provider;1"; diff --git a/dom/tests/unit/test_geolocation_reset_accuracy_wrap.js b/dom/tests/unit/test_geolocation_reset_accuracy_wrap.js index b44a97e7934d..84a4ac27db87 100644 --- a/dom/tests/unit/test_geolocation_reset_accuracy_wrap.js +++ b/dom/tests/unit/test_geolocation_reset_accuracy_wrap.js @@ -1,5 +1,5 @@ -var Cc = Components.classes; -var Ci = Components.interfaces; +const Cc = Components.classes; +const Ci = Components.interfaces; const providerCID = Components.ID("{14aa4b81-e266-45cb-88f8-89595dece114}"); const providerContract = "@mozilla.org/geolocation/provider;1"; diff --git a/dom/tests/unit/test_geolocation_timeout.js b/dom/tests/unit/test_geolocation_timeout.js index cfe0ba737547..a3f400b2e905 100644 --- a/dom/tests/unit/test_geolocation_timeout.js +++ b/dom/tests/unit/test_geolocation_timeout.js @@ -1,7 +1,7 @@ -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; -var Cr = Components.results; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; Cu.import("resource://testing-common/httpd.js"); diff --git a/dom/tests/unit/test_geolocation_timeout_wrap.js b/dom/tests/unit/test_geolocation_timeout_wrap.js index 1f87bec7eb0b..514c3f9b3a74 100644 --- a/dom/tests/unit/test_geolocation_timeout_wrap.js +++ b/dom/tests/unit/test_geolocation_timeout_wrap.js @@ -1,6 +1,6 @@ -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; Cu.import("resource://testing-common/httpd.js"); diff --git a/dom/wappush/gonk/WapPushManager.js b/dom/wappush/gonk/WapPushManager.js index 96f8459b734a..62c6951ee3f1 100644 --- a/dom/wappush/gonk/WapPushManager.js +++ b/dom/wappush/gonk/WapPushManager.js @@ -4,7 +4,7 @@ "use strict"; -var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); diff --git a/dom/wappush/tests/header_helpers.js b/dom/wappush/tests/header_helpers.js index 8adb519651fa..c8de79823510 100644 --- a/dom/wappush/tests/header_helpers.js +++ b/dom/wappush/tests/header_helpers.js @@ -3,7 +3,7 @@ "use strict"; -var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; var subscriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"] diff --git a/dom/workers/test/dom_worker_helper.js b/dom/workers/test/dom_worker_helper.js index 9827e86093ef..edc404219c07 100644 --- a/dom/workers/test/dom_worker_helper.js +++ b/dom/workers/test/dom_worker_helper.js @@ -3,7 +3,7 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ -var { classes: Cc, interfaces: Ci, utils: Cu } = Components; +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; Cu.import("resource://gre/modules/AddonManager.jsm"); Cu.import("resource://gre/modules/Services.jsm"); diff --git a/dom/workers/test/extensions/bootstrap/bootstrap.js b/dom/workers/test/extensions/bootstrap/bootstrap.js index d0064c4bbe5f..7bc77b7300b7 100644 --- a/dom/workers/test/extensions/bootstrap/bootstrap.js +++ b/dom/workers/test/extensions/bootstrap/bootstrap.js @@ -3,8 +3,8 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ -var Ci = Components.interfaces; -var Cu = Components.utils; +const Ci = Components.interfaces; +const Cu = Components.utils; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); diff --git a/embedding/test/browser_bug1204626.js b/embedding/test/browser_bug1204626.js index 165cb9b43a9c..80494290b2c7 100644 --- a/embedding/test/browser_bug1204626.js +++ b/embedding/test/browser_bug1204626.js @@ -1,6 +1,6 @@ "use strict"; // -*- js-indent-level: 2; indent-tabs-mode: nil -*- -var Cc = Components.classes; -var Ci = Components.interfaces; +const Cc = Components.classes; +const Ci = Components.interfaces; const contentBase = "https://example.com/browser/embedding/test/"; const chromeBase = "chrome://mochitests/content/browser/embedding/test/"; const testPageURL = contentBase + "bug1204626_doc0.html"; diff --git a/embedding/tests/unit/test_wwauthpromptfactory.js b/embedding/tests/unit/test_wwauthpromptfactory.js index 358e5ca6dacd..aba2cf684f6e 100644 --- a/embedding/tests/unit/test_wwauthpromptfactory.js +++ b/embedding/tests/unit/test_wwauthpromptfactory.js @@ -1,5 +1,5 @@ -var Cc = Components.classes; -var Ci = Components.interfaces; +const Cc = Components.classes; +const Ci = Components.interfaces; var authPromptRequestReceived; diff --git a/extensions/cookie/test/unit/cookieprompt.js b/extensions/cookie/test/unit/cookieprompt.js index c0a17e0060f7..fa4257caf9ee 100644 --- a/extensions/cookie/test/unit/cookieprompt.js +++ b/extensions/cookie/test/unit/cookieprompt.js @@ -3,7 +3,7 @@ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); -var Ci = Components.interfaces; +const Ci = Components.interfaces; function CookiePromptService() { } diff --git a/extensions/cookie/test/unit/head_cookies.js b/extensions/cookie/test/unit/head_cookies.js index fe4c0a53dc53..33b515566e05 100644 --- a/extensions/cookie/test/unit/head_cookies.js +++ b/extensions/cookie/test/unit/head_cookies.js @@ -6,9 +6,9 @@ Components.utils.import("resource://gre/modules/Services.jsm"); Components.utils.import("resource://gre/modules/NetUtil.jsm"); Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cr = Components.results; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cr = Components.results; XPCOMUtils.defineLazyServiceGetter(Services, "cookies", "@mozilla.org/cookieService;1", diff --git a/extensions/cookie/test/unit_ipc/test_child.js b/extensions/cookie/test/unit_ipc/test_child.js index 49cb2f69f900..ae81da05c2a5 100644 --- a/extensions/cookie/test/unit_ipc/test_child.js +++ b/extensions/cookie/test/unit_ipc/test_child.js @@ -1,6 +1,6 @@ -var Ci = Components.interfaces; -var Cc = Components.classes; -var Cr = Components.results; +const Ci = Components.interfaces; +const Cc = Components.classes; +const Cr = Components.results; var gIoService = Components.classes["@mozilla.org/network/io-service;1"] .getService(Components.interfaces.nsIIOService); diff --git a/extensions/cookie/test/unit_ipc/test_parent.js b/extensions/cookie/test/unit_ipc/test_parent.js index 5423dd594240..b1056146c0f6 100644 --- a/extensions/cookie/test/unit_ipc/test_parent.js +++ b/extensions/cookie/test/unit_ipc/test_parent.js @@ -1,6 +1,6 @@ -var Ci = Components.interfaces; -var Cc = Components.classes; -var Cr = Components.results; +const Ci = Components.interfaces; +const Cc = Components.classes; +const Cr = Components.results; var gIoService = Components.classes["@mozilla.org/network/io-service;1"] .getService(Components.interfaces.nsIIOService); diff --git a/extensions/spellcheck/hunspell/tests/unit/test_hunspell.js b/extensions/spellcheck/hunspell/tests/unit/test_hunspell.js index 7eba0e0e305d..7ade10db448b 100644 --- a/extensions/spellcheck/hunspell/tests/unit/test_hunspell.js +++ b/extensions/spellcheck/hunspell/tests/unit/test_hunspell.js @@ -2,8 +2,8 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ -var Cc = Components.classes; -var Ci = Components.interfaces; +const Cc = Components.classes; +const Ci = Components.interfaces; const tests = [ ["affixes", "iso-8859-1"], diff --git a/extensions/spellcheck/tests/mochitest/helper_bug1170484.js b/extensions/spellcheck/tests/mochitest/helper_bug1170484.js index 0a26448eedc5..689c2c0746f3 100644 --- a/extensions/spellcheck/tests/mochitest/helper_bug1170484.js +++ b/extensions/spellcheck/tests/mochitest/helper_bug1170484.js @@ -1,5 +1,5 @@ -var Cu = Components.utils; -var Ci = Components.interfaces; +const Cu = Components.utils; +const Ci = Components.interfaces; Cu.import("resource://gre/modules/Services.jsm"); diff --git a/extensions/universalchardet/tests/CharsetDetectionTests.js b/extensions/universalchardet/tests/CharsetDetectionTests.js index 6ccc9c3f1b76..8d975170abe6 100644 --- a/extensions/universalchardet/tests/CharsetDetectionTests.js +++ b/extensions/universalchardet/tests/CharsetDetectionTests.js @@ -5,8 +5,8 @@ var gOldPref; var gDetectorList; var gTestIndex; var gLocalDir; -var Cc = Components.classes; -var Ci = Components.interfaces; +const Cc = Components.classes; +const Ci = Components.interfaces; function CharsetDetectionTests(aTestFile, aExpectedCharset, aDetectorList) { diff --git a/image/test/unit/async_load_tests.js b/image/test/unit/async_load_tests.js index a1705f243cb4..1ab401169742 100644 --- a/image/test/unit/async_load_tests.js +++ b/image/test/unit/async_load_tests.js @@ -6,10 +6,10 @@ * var uri. */ -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; -var Cr = Components.results; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; Cu.import("resource://testing-common/httpd.js"); Cu.import("resource://gre/modules/Services.jsm"); diff --git a/image/test/unit/test_encoder_apng.js b/image/test/unit/test_encoder_apng.js index e7b90c28bc31..22d663897723 100644 --- a/image/test/unit/test_encoder_apng.js +++ b/image/test/unit/test_encoder_apng.js @@ -4,8 +4,8 @@ */ -var Ci = Components.interfaces; -var Cc = Components.classes; +const Ci = Components.interfaces; +const Cc = Components.classes; // dispose=[none|background|previous] // blend=[source|over] diff --git a/image/test/unit/test_encoder_png.js b/image/test/unit/test_encoder_png.js index 67beb840fe66..c434f23e0ea7 100644 --- a/image/test/unit/test_encoder_png.js +++ b/image/test/unit/test_encoder_png.js @@ -3,8 +3,8 @@ * */ -var Ci = Components.interfaces; -var Cc = Components.classes; +const Ci = Components.interfaces; +const Cc = Components.classes; var png1A = { // A 3x3 image, rows are red, green, blue. diff --git a/image/test/unit/test_imgtools.js b/image/test/unit/test_imgtools.js index f7bd7c1c5074..64361adfee62 100644 --- a/image/test/unit/test_imgtools.js +++ b/image/test/unit/test_imgtools.js @@ -2,8 +2,8 @@ * Tests for imgITools */ -var Ci = Components.interfaces; -var Cc = Components.classes; +const Ci = Components.interfaces; +const Cc = Components.classes; /* diff --git a/image/test/unit/test_moz_icon_uri.js b/image/test/unit/test_moz_icon_uri.js index 5e697fb21eda..c179c9f06b44 100644 --- a/image/test/unit/test_moz_icon_uri.js +++ b/image/test/unit/test_moz_icon_uri.js @@ -3,8 +3,8 @@ * */ -var Ci = Components.interfaces; -var Cc = Components.classes; +const Ci = Components.interfaces; +const Cc = Components.classes; // There are 3 types of valid icon URIs: // 1. moz-icon:[valid URL] diff --git a/image/test/unit/test_private_channel.js b/image/test/unit/test_private_channel.js index da72d1bb1f8a..e96b6afaffcf 100644 --- a/image/test/unit/test_private_channel.js +++ b/image/test/unit/test_private_channel.js @@ -1,7 +1,7 @@ -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cr = Components.results; -var Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cr = Components.results; +const Cu = Components.utils; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://testing-common/httpd.js"); diff --git a/intl/locale/tests/unit/test_bug22310.js b/intl/locale/tests/unit/test_bug22310.js index 7d98ba683506..1e0ff96cb5b9 100644 --- a/intl/locale/tests/unit/test_bug22310.js +++ b/intl/locale/tests/unit/test_bug22310.js @@ -1,7 +1,7 @@ String.prototype.has = function(s) { return this.indexOf(s) != -1; } -var Cc = Components.classes; -var Ci = Components.interfaces; +const Cc = Components.classes; +const Ci = Components.interfaces; const dts = Cc["@mozilla.org/intl/scriptabledateformat;1"] .getService(Ci.nsIScriptableDateFormat); diff --git a/intl/locale/tests/unit/test_bug371611.js b/intl/locale/tests/unit/test_bug371611.js index 807c9ecc591f..bcc4d86dbcfb 100644 --- a/intl/locale/tests/unit/test_bug371611.js +++ b/intl/locale/tests/unit/test_bug371611.js @@ -1,6 +1,6 @@ -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cr = Components.results; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cr = Components.results; function test_formatdatetime_return() { diff --git a/intl/locale/tests/unit/test_collation_mac_icu.js b/intl/locale/tests/unit/test_collation_mac_icu.js index d04d301c5d17..37facfd9a8a7 100644 --- a/intl/locale/tests/unit/test_collation_mac_icu.js +++ b/intl/locale/tests/unit/test_collation_mac_icu.js @@ -1,4 +1,4 @@ -var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; Cu.import("resource://gre/modules/Services.jsm"); diff --git a/intl/uconv/tests/unit/CharsetConversionTests.js b/intl/uconv/tests/unit/CharsetConversionTests.js index 72480a5f8803..02dcc08d7497 100644 --- a/intl/uconv/tests/unit/CharsetConversionTests.js +++ b/intl/uconv/tests/unit/CharsetConversionTests.js @@ -1,6 +1,6 @@ -var Ci = Components.interfaces; -var Cc = Components.classes; -var CC = Components.Constructor; +const Ci = Components.interfaces; +const Cc = Components.classes; +const CC = Components.Constructor; function CreateScriptableConverter() { diff --git a/intl/uconv/tests/unit/test_bug317216.js b/intl/uconv/tests/unit/test_bug317216.js index 52a27f8bfe0f..8834a62fb8e4 100644 --- a/intl/uconv/tests/unit/test_bug317216.js +++ b/intl/uconv/tests/unit/test_bug317216.js @@ -9,8 +9,8 @@ * UTF16 character and mid-surrogate pair */ -var Ci = Components.interfaces; -var Cu = Components.utils; +const Ci = Components.interfaces; +const Cu = Components.utils; Cu.import("resource://gre/modules/Services.jsm"); diff --git a/intl/uconv/tests/unit/test_bug340714.js b/intl/uconv/tests/unit/test_bug340714.js index 1f2fae9da182..0a6451d27891 100644 --- a/intl/uconv/tests/unit/test_bug340714.js +++ b/intl/uconv/tests/unit/test_bug340714.js @@ -11,8 +11,8 @@ * is an eight-bit character. */ -var Ci = Components.interfaces; -var Cu = Components.utils; +const Ci = Components.interfaces; +const Cu = Components.utils; Cu.import("resource://gre/modules/Services.jsm"); diff --git a/intl/uconv/tests/unit/test_bug563618.js b/intl/uconv/tests/unit/test_bug563618.js index 8bc52165e3db..dd80c8e98555 100644 --- a/intl/uconv/tests/unit/test_bug563618.js +++ b/intl/uconv/tests/unit/test_bug563618.js @@ -4,8 +4,8 @@ * */ -var Ci = Components.interfaces; -var Cu = Components.utils; +const Ci = Components.interfaces; +const Cu = Components.utils; Cu.import("resource://gre/modules/Services.jsm"); diff --git a/intl/uconv/tests/unit/test_charset_conversion.js b/intl/uconv/tests/unit/test_charset_conversion.js index 4111a85fa018..88200d96d869 100644 --- a/intl/uconv/tests/unit/test_charset_conversion.js +++ b/intl/uconv/tests/unit/test_charset_conversion.js @@ -1,5 +1,5 @@ -var Cc = Components.classes; -var Ci = Components.interfaces; +const Cc = Components.classes; +const Ci = Components.interfaces; const NS_ERROR_ILLEGAL_VALUE = Components.results.NS_ERROR_ILLEGAL_VALUE; diff --git a/intl/uconv/tests/unit/test_utf8_illegals.js b/intl/uconv/tests/unit/test_utf8_illegals.js index 9a7d7a588933..c770247309e6 100644 --- a/intl/uconv/tests/unit/test_utf8_illegals.js +++ b/intl/uconv/tests/unit/test_utf8_illegals.js @@ -1,8 +1,8 @@ // Tests illegal UTF-8 sequences -var Cc = Components.Constructor; -var Ci = Components.interfaces; -var Cu = Components.utils; +const Cc = Components.Constructor; +const Ci = Components.interfaces; +const Cu = Components.utils; Cu.import("resource://gre/modules/Services.jsm"); diff --git a/ipc/testshell/tests/test_ipcshell_child.js b/ipc/testshell/tests/test_ipcshell_child.js index d9c9fb6c0dfc..a6ba074055e7 100644 --- a/ipc/testshell/tests/test_ipcshell_child.js +++ b/ipc/testshell/tests/test_ipcshell_child.js @@ -1,5 +1,5 @@ -var Cc = Components.classes; -var Ci = Components.interfaces; +const Cc = Components.classes; +const Ci = Components.interfaces; const runtime = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime); diff --git a/js/xpconnect/tests/chrome/test_bug793433.xul b/js/xpconnect/tests/chrome/test_bug793433.xul index f77c12aa14d2..f48e1c4f48ff 100644 --- a/js/xpconnect/tests/chrome/test_bug793433.xul +++ b/js/xpconnect/tests/chrome/test_bug793433.xul @@ -19,8 +19,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=793433 + + +

+ +

+  
+  
- { - let utils = {}; - Components.utils.import("resource://gre/modules/DownloadUtils.jsm", utils); - utils.DownloadUtils; - } + let utils = {}; + Components.utils.import("resource://gre/modules/DownloadUtils.jsm", utils); + utils.DownloadUtils; @@ -2678,13 +2676,11 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/. ]]> document.getAnonymousElementByAttribute(this, "anonid", "promo-message"); diff --git a/browser/components/customizableui/content/panelUI.js b/browser/components/customizableui/content/panelUI.js index b03a44aca7a9..d8722b2734d0 100644 --- a/browser/components/customizableui/content/panelUI.js +++ b/browser/components/customizableui/content/panelUI.js @@ -510,8 +510,6 @@ const PanelUI = { }, }; -XPCOMUtils.defineConstant(this, "PanelUI", PanelUI); - /** * Gets the currently selected locale for display. * @return the selected locale or "en-US" if none is selected diff --git a/browser/components/customizableui/test/browser_1096763_seen_widgets_post_reset.js b/browser/components/customizableui/test/browser_1096763_seen_widgets_post_reset.js index b707ca10e3c4..7f4e0e28d326 100644 --- a/browser/components/customizableui/test/browser_1096763_seen_widgets_post_reset.js +++ b/browser/components/customizableui/test/browser_1096763_seen_widgets_post_reset.js @@ -9,18 +9,17 @@ add_task(function*() { defaultArea: CustomizableUI.AREA_NAVBAR }); - const kPrefCustomizationState = "browser.uiCustomization.state"; let bsPass = Cu.import("resource:///modules/CustomizableUI.jsm", {}); ok(bsPass.gSeenWidgets.has(BUTTONID), "Widget should be seen after createWidget is called."); CustomizableUI.reset(); ok(bsPass.gSeenWidgets.has(BUTTONID), "Widget should still be seen after reset."); - ok(!Services.prefs.prefHasUserValue(kPrefCustomizationState), "Pref shouldn't be set right now, because that'd break undo."); + ok(!Services.prefs.prefHasUserValue(bsPass.kPrefCustomizationState), "Pref shouldn't be set right now, because that'd break undo."); CustomizableUI.addWidgetToArea(BUTTONID, CustomizableUI.AREA_NAVBAR); gCustomizeMode.removeFromArea(document.getElementById(BUTTONID)); - let hasUserValue = Services.prefs.prefHasUserValue(kPrefCustomizationState); + let hasUserValue = Services.prefs.prefHasUserValue(bsPass.kPrefCustomizationState); ok(hasUserValue, "Pref should be set right now."); if (hasUserValue) { - let seenArray = JSON.parse(Services.prefs.getCharPref(kPrefCustomizationState)).seen; + let seenArray = JSON.parse(Services.prefs.getCharPref(bsPass.kPrefCustomizationState)).seen; isnot(seenArray.indexOf(BUTTONID), -1, "Widget should be in saved 'seen' list."); } }); diff --git a/browser/components/downloads/content/downloads.js b/browser/components/downloads/content/downloads.js index de17c5d760bb..276bdda3deda 100644 --- a/browser/components/downloads/content/downloads.js +++ b/browser/components/downloads/content/downloads.js @@ -580,8 +580,6 @@ const DownloadsPanel = { }, }; -XPCOMUtils.defineConstant(this, "DownloadsPanel", DownloadsPanel); - //////////////////////////////////////////////////////////////////////////////// //// DownloadsOverlayLoader @@ -660,8 +658,6 @@ const DownloadsOverlayLoader = { }, }; -XPCOMUtils.defineConstant(this, "DownloadsOverlayLoader", DownloadsOverlayLoader); - //////////////////////////////////////////////////////////////////////////////// //// DownloadsView @@ -1008,8 +1004,6 @@ const DownloadsView = { }, } -XPCOMUtils.defineConstant(this, "DownloadsView", DownloadsView); - //////////////////////////////////////////////////////////////////////////////// //// DownloadsViewItem @@ -1148,8 +1142,6 @@ const DownloadsViewController = { } }; -XPCOMUtils.defineConstant(this, "DownloadsViewController", DownloadsViewController); - //////////////////////////////////////////////////////////////////////////////// //// DownloadsViewItemController @@ -1496,9 +1488,7 @@ const DownloadsSummary = { delete this._detailsNode; return this._detailsNode = node; } -}; - -XPCOMUtils.defineConstant(this, "DownloadsSummary", DownloadsSummary); +} //////////////////////////////////////////////////////////////////////////////// //// DownloadsFooter @@ -1552,5 +1542,3 @@ const DownloadsFooter = { return this._footerNode = node; } }; - -XPCOMUtils.defineConstant(this, "DownloadsFooter", DownloadsFooter); diff --git a/browser/components/downloads/content/indicator.js b/browser/components/downloads/content/indicator.js index b4df74c6067d..9261c4997386 100644 --- a/browser/components/downloads/content/indicator.js +++ b/browser/components/downloads/content/indicator.js @@ -577,8 +577,3 @@ const DownloadsIndicatorView = { }, }; -Object.defineProperty(this, "DownloadsIndicatorView", { - value: DownloadsIndicatorView, - enumerable: true, - writable: false -}); diff --git a/browser/components/loop/modules/LoopRoomsCache.jsm b/browser/components/loop/modules/LoopRoomsCache.jsm index 16e37dd256b9..c1915723c755 100644 --- a/browser/components/loop/modules/LoopRoomsCache.jsm +++ b/browser/components/loop/modules/LoopRoomsCache.jsm @@ -17,7 +17,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm this.EXPORTED_SYMBOLS = ["LoopRoomsCache"]; const LOOP_ROOMS_CACHE_FILENAME = "loopRoomsCache.json"; -XPCOMUtils.defineConstant(this, "LOOP_ROOMS_CACHE_FILENAME", LOOP_ROOMS_CACHE_FILENAME); /** * RoomsCache is a cache for saving simple rooms data to the disk in case we diff --git a/browser/components/loop/modules/MozLoopService.jsm b/browser/components/loop/modules/MozLoopService.jsm index 7de2d97d5ff6..ef63a91e2c46 100644 --- a/browser/components/loop/modules/MozLoopService.jsm +++ b/browser/components/loop/modules/MozLoopService.jsm @@ -112,14 +112,6 @@ this.EXPORTED_SYMBOLS = ["MozLoopService", "LOOP_SESSION_TYPE", "TWO_WAY_MEDIA_CONN_LENGTH", "SHARING_STATE_CHANGE", "SHARING_ROOM_URL", "ROOM_CREATE", "ROOM_DELETE", "ROOM_CONTEXT_ADD"]; -XPCOMUtils.defineConstant(this, "LOOP_SESSION_TYPE", LOOP_SESSION_TYPE); -XPCOMUtils.defineConstant(this, "TWO_WAY_MEDIA_CONN_LENGTH", TWO_WAY_MEDIA_CONN_LENGTH); -XPCOMUtils.defineConstant(this, "SHARING_STATE_CHANGE", SHARING_STATE_CHANGE); -XPCOMUtils.defineConstant(this, "SHARING_ROOM_URL", SHARING_ROOM_URL); -XPCOMUtils.defineConstant(this, "ROOM_CREATE", ROOM_CREATE); -XPCOMUtils.defineConstant(this, "ROOM_DELETE", ROOM_DELETE); -XPCOMUtils.defineConstant(this, "ROOM_CONTEXT_ADD", ROOM_CONTEXT_ADD); - XPCOMUtils.defineLazyModuleGetter(this, "injectLoopAPI", "resource:///modules/loop/MozLoopAPI.jsm"); diff --git a/browser/components/sessionstore/test/browser_privatetabs.js b/browser/components/sessionstore/test/browser_privatetabs.js index 7b296bbbf05d..12d8a7bfe89e 100644 --- a/browser/components/sessionstore/test/browser_privatetabs.js +++ b/browser/components/sessionstore/test/browser_privatetabs.js @@ -1,6 +1,10 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ +var Imports = {}; +Cu.import("resource:///modules/sessionstore/SessionSaver.jsm", Imports); +var {SessionSaver} = Imports; + add_task(function cleanup() { info("Forgetting closed tabs"); while (ss.getClosedTabCount(window)) { diff --git a/browser/experiments/Experiments.jsm b/browser/experiments/Experiments.jsm index 739ed5bb8fca..f91ab3778840 100644 --- a/browser/experiments/Experiments.jsm +++ b/browser/experiments/Experiments.jsm @@ -94,7 +94,6 @@ const TELEMETRY_LOG = { RECHECK: "RECHECK", }, }; -XPCOMUtils.defineConstant(this, "TELEMETRY_LOG", TELEMETRY_LOG); const gPrefs = new Preferences(PREF_BRANCH); const gPrefsTelemetry = new Preferences(PREF_BRANCH_TELEMETRY); diff --git a/browser/modules/Windows8WindowFrameColor.jsm b/browser/modules/Windows8WindowFrameColor.jsm index 429d970ca954..cb52ad62696d 100644 --- a/browser/modules/Windows8WindowFrameColor.jsm +++ b/browser/modules/Windows8WindowFrameColor.jsm @@ -11,7 +11,7 @@ Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); var Registry = Cu.import("resource://gre/modules/WindowsRegistry.jsm").WindowsRegistry; -var Windows8WindowFrameColor = { +const Windows8WindowFrameColor = { _windowFrameColor: null, get: function() { diff --git a/devtools/client/canvasdebugger/canvasdebugger.js b/devtools/client/canvasdebugger/canvasdebugger.js index c39bd04dc212..11d5835034e9 100644 --- a/devtools/client/canvasdebugger/canvasdebugger.js +++ b/devtools/client/canvasdebugger/canvasdebugger.js @@ -77,7 +77,6 @@ const EVENTS = { SOURCE_SHOWN_IN_JS_DEBUGGER: "CanvasDebugger:SourceShownInJsDebugger", SOURCE_NOT_FOUND_IN_JS_DEBUGGER: "CanvasDebugger:SourceNotFoundInJsDebugger" }; -XPCOMUtils.defineConstant(this, "EVENTS", EVENTS); const HTML_NS = "http://www.w3.org/1999/xhtml"; const STRINGS_URI = "chrome://browser/locale/devtools/canvasdebugger.properties"; diff --git a/devtools/client/debugger/debugger-controller.js b/devtools/client/debugger/debugger-controller.js index 6fc0137b6ff2..cd1fee18e070 100644 --- a/devtools/client/debugger/debugger-controller.js +++ b/devtools/client/debugger/debugger-controller.js @@ -104,7 +104,6 @@ Cu.import("resource:///modules/devtools/client/shared/widgets/ViewHelpers.jsm"); Cu.import("resource:///modules/devtools/client/shared/browser-loader.js"); const require = BrowserLoader("resource:///modules/devtools/client/debugger/", this).require; -XPCOMUtils.defineConstant(this, "require", require); const {TargetFactory} = require("devtools/client/framework/target"); const {Toolbox} = require("devtools/client/framework/toolbox"); @@ -115,8 +114,6 @@ const DebuggerEditor = require("devtools/client/sourceeditor/debugger"); const {Tooltip} = require("devtools/client/shared/widgets/Tooltip"); const FastListWidget = require("devtools/client/shared/widgets/FastListWidget"); -XPCOMUtils.defineConstant(this, "EVENTS", EVENTS); - XPCOMUtils.defineLazyModuleGetter(this, "Task", "resource://gre/modules/Task.jsm"); diff --git a/devtools/client/debugger/debugger-view.js b/devtools/client/debugger/debugger-view.js index 47afbe9c9e07..1dcf5d5aaa8f 100644 --- a/devtools/client/debugger/debugger-view.js +++ b/devtools/client/debugger/debugger-view.js @@ -49,19 +49,6 @@ const services = { const EventListenersView = require('./content/views/event-listeners-view'); const actions = require('./content/actions/event-listeners'); -Object.defineProperties(this, { - "store": { - value: store, - enumerable: true, - writable: false - }, - "services": { - value: services, - enumerable: true, - writable: false - } -}); - /** * Object defining the debugger view components. */ diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_break-on-next-console.js b/devtools/client/debugger/test/mochitest/browser_dbg_break-on-next-console.js index 4fe42eb6438f..ff259780cc2e 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_break-on-next-console.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_break-on-next-console.js @@ -40,13 +40,11 @@ function test() { let updatedFrame = yield waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES); let variables = gDebugger.DebuggerView.Variables; - is(variables._store.length, 3, "Correct number of scopes available"); + is(variables._store.length, 2, "Correct number of scopes available"); is(variables.getScopeAtIndex(0).name, "With scope [Object]", "Paused with correct scope (0)"); - is(variables.getScopeAtIndex(1).name, "Block scope", + is(variables.getScopeAtIndex(1).name, "Global scope [Window]", "Paused with correct scope (1)"); - is(variables.getScopeAtIndex(2).name, "Global scope [Window]", - "Paused with correct scope (2)"); let onceResumed = gTarget.once("thread-resumed"); EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger); diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_break-on-next.js b/devtools/client/debugger/test/mochitest/browser_dbg_break-on-next.js index edded224faa2..af7064ee8c62 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_break-on-next.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_break-on-next.js @@ -49,15 +49,13 @@ function test() { let updatedFrame = yield waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES); let variables = gDebugger.DebuggerView.Variables; - is(variables._store.length, 4, "Correct number of scopes available"); + is(variables._store.length, 3, "Correct number of scopes available"); is(variables.getScopeAtIndex(0).name, "Function scope [interval<]", "Paused with correct scope (0)"); is(variables.getScopeAtIndex(1).name, "Block scope", "Paused with correct scope (1)"); - is(variables.getScopeAtIndex(2).name, "Block scope", + is(variables.getScopeAtIndex(2).name, "Global scope [Window]", "Paused with correct scope (2)"); - is(variables.getScopeAtIndex(3).name, "Global scope [Window]", - "Paused with correct scope (3)"); yield evalInTab(gTab, "clearInterval(interval)"); let onceResumed = gTarget.once("thread-resumed"); @@ -78,21 +76,15 @@ function test() { let updatedFrame = yield waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES); let variables = gDebugger.DebuggerView.Variables; - is(variables._store.length, 6, "Correct number of scopes available"); + is(variables._store.length, 4, "Correct number of scopes available"); is(variables.getScopeAtIndex(0).name, "Function scope [onclick]", "Paused with correct scope (0)"); - // Non-syntactic lexical scope introduced by non-syntactic scope chain. - is(variables.getScopeAtIndex(1).name, "Block scope", + is(variables.getScopeAtIndex(1).name, "With scope [HTMLButtonElement]", "Paused with correct scope (1)"); - is(variables.getScopeAtIndex(2).name, "With scope [HTMLButtonElement]", + is(variables.getScopeAtIndex(2).name, "With scope [HTMLDocument]", "Paused with correct scope (2)"); - is(variables.getScopeAtIndex(3).name, "With scope [HTMLDocument]", + is(variables.getScopeAtIndex(3).name, "Global scope [Window]", "Paused with correct scope (3)"); - // Global lexical scope. - is(variables.getScopeAtIndex(4).name, "Block scope", - "Paused with correct scope (4)"); - is(variables.getScopeAtIndex(5).name, "Global scope [Window]", - "Paused with correct scope (5)"); let onceResumed = gTarget.once("thread-resumed"); EventUtils.sendMouseEvent({ type: "mousedown" }, gResumeButton, gDebugger); diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_pause-exceptions-01.js b/devtools/client/debugger/test/mochitest/browser_dbg_pause-exceptions-01.js index bb0775590ea7..edfb63dc161e 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_pause-exceptions-01.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_pause-exceptions-01.js @@ -53,8 +53,8 @@ function testPauseOnExceptionsDisabled() { is(gFrames.itemCount, 1, "Should have one frame."); - is(gVariables._store.length, 4, - "Should have four scopes."); + is(gVariables._store.length, 3, + "Should have three scopes."); is(innerNodes[0].querySelector(".name").getAttribute("value"), "this", "Should have the right property name for 'this'."); @@ -96,8 +96,8 @@ function testPauseOnExceptionsEnabled() { is(gFrames.itemCount, 1, "Should have one frame."); - is(gVariables._store.length, 4, - "Should have four scopes."); + is(gVariables._store.length, 3, + "Should have three scopes."); is(innerNodes[0].querySelector(".name").getAttribute("value"), "", "Should have the right property name for ."); @@ -117,8 +117,8 @@ function testPauseOnExceptionsEnabled() { is(gFrames.itemCount, 1, "Should have one frame."); - is(gVariables._store.length, 4, - "Should have four scopes."); + is(gVariables._store.length, 3, + "Should have three scopes."); is(innerNodes[0].querySelector(".name").getAttribute("value"), "this", "Should have the right property name for 'this'."); diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_pause-exceptions-02.js b/devtools/client/debugger/test/mochitest/browser_dbg_pause-exceptions-02.js index 547e86b5c273..f44f6c3ddb48 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_pause-exceptions-02.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_pause-exceptions-02.js @@ -52,8 +52,8 @@ function testPauseOnExceptionsAfterReload() { is(gFrames.itemCount, 1, "Should have one frame."); - is(gVariables._store.length, 4, - "Should have four scopes."); + is(gVariables._store.length, 3, + "Should have three scopes."); is(innerNodes[0].querySelector(".name").getAttribute("value"), "", "Should have the right property name for ."); @@ -73,8 +73,8 @@ function testPauseOnExceptionsAfterReload() { is(gFrames.itemCount, 1, "Should have one frame."); - is(gVariables._store.length, 4, - "Should have four scopes."); + is(gVariables._store.length, 3, + "Should have three scopes."); is(innerNodes[0].querySelector(".name").getAttribute("value"), "this", "Should have the right property name for 'this'."); diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-06.js b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-06.js index f02a03ff386e..fa6901d081bd 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-06.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-06.js @@ -7,7 +7,7 @@ const TAB_URL = EXAMPLE_URL + "doc_promise.html"; -var test = Task.async(function* () { +const test = Task.async(function* () { const [tab,, panel] = yield initDebugger(TAB_URL); yield ensureSourceIs(panel, "doc_promise.html", true); diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-01.js b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-01.js index cc864c9a04a8..b3f1bd49ab94 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-01.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-01.js @@ -44,8 +44,7 @@ function testVariablesAndPropertiesFiltering() { let localScope = gVariables.getScopeAtIndex(0); let withScope = gVariables.getScopeAtIndex(1); let functionScope = gVariables.getScopeAtIndex(2); - let globalLexicalScope = gVariables.getScopeAtIndex(3); - let globalScope = gVariables.getScopeAtIndex(4); + let globalScope = gVariables.getScopeAtIndex(3); let protoVar = localScope.get("__proto__"); let constrVar = protoVar.get("constructor"); let proto2Var = constrVar.get("__proto__"); @@ -58,8 +57,6 @@ function testVariablesAndPropertiesFiltering() { "The withScope should be expanded."); is(functionScope.expanded, true, "The functionScope should be expanded."); - is(globalLexicalScope.expanded, true, - "The globalLexicalScope should be expanded."); is(globalScope.expanded, true, "The globalScope should be expanded."); @@ -78,8 +75,6 @@ function testVariablesAndPropertiesFiltering() { "There should be 0 variables displayed in the with scope."); is(functionScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 0, "There should be 0 variables displayed in the function scope."); - is(globalLexicalScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 0, - "There should be 0 variables displayed in the global lexical scope."); is(globalScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 0, "There should be 0 variables displayed in the global scope."); @@ -87,8 +82,6 @@ function testVariablesAndPropertiesFiltering() { "There should be 0 properties displayed in the with scope."); is(functionScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 0, "There should be 0 properties displayed in the function scope."); - is(globalLexicalScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 0, - "There should be 0 properties displayed in the global lexical scope."); is(globalScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 0, "There should be 0 properties displayed in the global scope."); @@ -113,7 +106,6 @@ function testVariablesAndPropertiesFiltering() { localScope.collapse(); withScope.collapse(); functionScope.collapse(); - globalLexicalScope.collapse(); globalScope.collapse(); protoVar.collapse(); constrVar.collapse(); @@ -126,8 +118,6 @@ function testVariablesAndPropertiesFiltering() { "The withScope should not be expanded."); is(functionScope.expanded, false, "The functionScope should not be expanded."); - is(globalLexicalScope.expanded, false, - "The globalLexicalScope should not be expanded."); is(globalScope.expanded, false, "The globalScope should not be expanded."); @@ -155,17 +145,14 @@ function prepareVariablesAndProperties() { let localScope = gVariables.getScopeAtIndex(0); let withScope = gVariables.getScopeAtIndex(1); let functionScope = gVariables.getScopeAtIndex(2); - let globalLexicalScope = gVariables.getScopeAtIndex(3); - let globalScope = gVariables.getScopeAtIndex(4); + let globalScope = gVariables.getScopeAtIndex(3); is(localScope.expanded, true, "The localScope should be expanded."); is(withScope.expanded, false, "The withScope should not be expanded yet."); is(functionScope.expanded, false, - "The functionScope should not be expanded yet."); - is(globalLexicalScope.expanded, false, - "The globalLexicalScope should not be expanded yet."); + "The functionScope should not be expanded yet."); is(globalScope.expanded, false, "The globalScope should not be expanded yet."); @@ -177,9 +164,7 @@ function prepareVariablesAndProperties() { is(withScope.expanded, true, "The withScope should now be expanded."); is(functionScope.expanded, true, - "The functionScope should now be expanded."); - is(globalLexicalScope.expanded, true, - "The globalLexicalScope should be expanded."); + "The functionScope should now be expanded."); is(globalScope.expanded, true, "The globalScope should now be expanded."); @@ -221,7 +206,6 @@ function prepareVariablesAndProperties() { withScope.expand(); functionScope.expand(); - globalLexicalScope.expand(); globalScope.expand(); return deferred.promise; diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-02.js b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-02.js index 80c9095327b9..240147089a1b 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-02.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-02.js @@ -44,8 +44,7 @@ function testVariablesAndPropertiesFiltering() { let localScope = gVariables.getScopeAtIndex(0); let withScope = gVariables.getScopeAtIndex(1); let functionScope = gVariables.getScopeAtIndex(2); - let globalLexicalScope = gVariables.getScopeAtIndex(3); - let globalScope = gVariables.getScopeAtIndex(4); + let globalScope = gVariables.getScopeAtIndex(3); let protoVar = localScope.get("__proto__"); let constrVar = protoVar.get("constructor"); let proto2Var = constrVar.get("__proto__"); @@ -58,8 +57,6 @@ function testVariablesAndPropertiesFiltering() { "The withScope should be expanded."); is(functionScope.expanded, true, "The functionScope should be expanded."); - is(globalLexicalScope.expanded, true, - "The globalScope should be expanded."); is(globalScope.expanded, true, "The globalScope should be expanded."); @@ -78,8 +75,6 @@ function testVariablesAndPropertiesFiltering() { "There should be 0 variables displayed in the with scope."); is(functionScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 0, "There should be 0 variables displayed in the function scope."); - is(globalLexicalScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 0, - "There should be no variables displayed in the global lexical scope."); is(globalScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 0, "There should be no variables displayed in the global scope."); @@ -89,8 +84,6 @@ function testVariablesAndPropertiesFiltering() { "There should be 0 properties displayed in the with scope."); is(functionScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 0, "There should be 0 properties displayed in the function scope."); - is(globalLexicalScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 0, - "There should be 0 properties displayed in the global lexical scope."); is(globalScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 0, "There should be 0 properties displayed in the global scope."); @@ -120,7 +113,6 @@ function testVariablesAndPropertiesFiltering() { localScope.collapse(); withScope.collapse(); functionScope.collapse(); - globalLexicalScope.collapse(); globalScope.collapse(); protoVar.collapse(); constrVar.collapse(); @@ -133,8 +125,6 @@ function testVariablesAndPropertiesFiltering() { "The withScope should not be expanded."); is(functionScope.expanded, false, "The functionScope should not be expanded."); - is(globalLexicalScope.expanded, false, - "The globalScope should not be expanded."); is(globalScope.expanded, false, "The globalScope should not be expanded."); @@ -163,8 +153,7 @@ function prepareVariablesAndProperties() { let localScope = gVariables.getScopeAtIndex(0); let withScope = gVariables.getScopeAtIndex(1); let functionScope = gVariables.getScopeAtIndex(2); - let globalLexicalScope = gVariables.getScopeAtIndex(3); - let globalScope = gVariables.getScopeAtIndex(4); + let globalScope = gVariables.getScopeAtIndex(3); is(localScope.expanded, true, "The localScope should be expanded."); @@ -172,8 +161,6 @@ function prepareVariablesAndProperties() { "The withScope should not be expanded yet."); is(functionScope.expanded, false, "The functionScope should not be expanded yet."); - is(globalLexicalScope.expanded, false, - "The globalScope should not be expanded yet."); is(globalScope.expanded, false, "The globalScope should not be expanded yet."); @@ -186,8 +173,6 @@ function prepareVariablesAndProperties() { "The withScope should now be expanded."); is(functionScope.expanded, true, "The functionScope should now be expanded."); - is(globalLexicalScope.expanded, true, - "The globalScope should now be expanded."); is(globalScope.expanded, true, "The globalScope should now be expanded."); @@ -229,7 +214,6 @@ function prepareVariablesAndProperties() { withScope.expand(); functionScope.expand(); - globalLexicalScope.expand(); globalScope.expand(); return deferred.promise; diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-03.js b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-03.js index a444b7e60a7e..88f5ff8cb99f 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-03.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-03.js @@ -43,8 +43,7 @@ function testVariablesAndPropertiesFiltering() { let localScope = gVariables.getScopeAtIndex(0); let withScope = gVariables.getScopeAtIndex(1); let functionScope = gVariables.getScopeAtIndex(2); - let globalLexicalScope = gVariables.getScopeAtIndex(3); - let globalScope = gVariables.getScopeAtIndex(4); + let globalScope = gVariables.getScopeAtIndex(3); function testFiltered() { is(localScope.expanded, true, @@ -53,8 +52,6 @@ function testVariablesAndPropertiesFiltering() { "The withScope should be expanded."); is(functionScope.expanded, true, "The functionScope should be expanded."); - is(globalLexicalScope.expanded, true, - "The globalScope should be expanded."); is(globalScope.expanded, true, "The globalScope should be expanded."); @@ -64,8 +61,6 @@ function testVariablesAndPropertiesFiltering() { "There should be 0 variables displayed in the with scope."); is(functionScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 0, "There should be 0 variables displayed in the function scope."); - is(globalLexicalScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 0, - "There should be 0 variables displayed in the global scope."); is(globalScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length, 0, "There should be 0 variables displayed in the global scope."); @@ -75,8 +70,6 @@ function testVariablesAndPropertiesFiltering() { "There should be 0 properties displayed in the with scope."); is(functionScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 0, "There should be 0 properties displayed in the function scope."); - is(globalLexicalScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 0, - "There should be 0 properties displayed in the global scope."); is(globalScope.target.querySelectorAll(".variables-view-property:not([unmatched])").length, 0, "There should be 0 properties displayed in the global scope."); } @@ -93,7 +86,6 @@ function testVariablesAndPropertiesFiltering() { localScope.collapse(); withScope.collapse(); functionScope.collapse(); - globalLexicalScope.collapse(); globalScope.collapse(); is(localScope.expanded, false, @@ -102,8 +94,6 @@ function testVariablesAndPropertiesFiltering() { "The withScope should not be expanded."); is(functionScope.expanded, false, "The functionScope should not be expanded."); - is(globalLexicalScope.expanded, false, - "The globalScope should not be expanded."); is(globalScope.expanded, false, "The globalScope should not be expanded."); @@ -125,8 +115,7 @@ function prepareVariablesAndProperties() { let localScope = gVariables.getScopeAtIndex(0); let withScope = gVariables.getScopeAtIndex(1); let functionScope = gVariables.getScopeAtIndex(2); - let globalLexicalScope = gVariables.getScopeAtIndex(3); - let globalScope = gVariables.getScopeAtIndex(4); + let globalScope = gVariables.getScopeAtIndex(3); is(localScope.expanded, true, "The localScope should be expanded."); @@ -134,8 +123,6 @@ function prepareVariablesAndProperties() { "The withScope should not be expanded yet."); is(functionScope.expanded, false, "The functionScope should not be expanded yet."); - is(globalLexicalScope.expanded, false, - "The globalScope should not be expanded yet."); is(globalScope.expanded, false, "The globalScope should not be expanded yet."); @@ -148,8 +135,6 @@ function prepareVariablesAndProperties() { "The withScope should now be expanded."); is(functionScope.expanded, true, "The functionScope should now be expanded."); - is(globalLexicalScope.expanded, true, - "The globalScope should now be expanded."); is(globalScope.expanded, true, "The globalScope should now be expanded."); @@ -158,7 +143,6 @@ function prepareVariablesAndProperties() { withScope.expand(); functionScope.expand(); - globalLexicalScope.expand(); globalScope.expand(); return deferred.promise; diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-04.js b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-04.js index ed69dbc6f831..1eb4748efbab 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-04.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-04.js @@ -44,110 +44,108 @@ function testVariablesAndPropertiesFiltering() { let localScope = gVariables.getScopeAtIndex(0); let withScope = gVariables.getScopeAtIndex(1); let functionScope = gVariables.getScopeAtIndex(2); - let globalLexicalScope = gVariables.getScopeAtIndex(3); - let globalScope = gVariables.getScopeAtIndex(4); + let globalScope = gVariables.getScopeAtIndex(3); let step = 0; let tests = [ function() { - assertExpansion([true, false, false, false, false]); + assertExpansion([true, false, false, false]); EventUtils.sendKey("RETURN", gDebugger); }, function() { - assertExpansion([true, false, false, false, false]); + assertExpansion([true, false, false, false]); EventUtils.sendKey("RETURN", gDebugger); }, function() { - assertExpansion([true, false, false, false, false]); + assertExpansion([true, false, false, false]); gEditor.focus(); }, function() { - assertExpansion([true, false, false, false, false]); + assertExpansion([true, false, false, false]); typeText(gSearchBox, "*"); }, function() { - assertExpansion([true, true, true, true, true]); + assertExpansion([true, true, true, true]); EventUtils.sendKey("RETURN", gDebugger); }, function() { - assertExpansion([true, true, true, true, true]); + assertExpansion([true, true, true, true]); EventUtils.sendKey("RETURN", gDebugger); }, function() { - assertExpansion([true, true, true, true, true]); + assertExpansion([true, true, true, true]); gEditor.focus(); }, function() { - assertExpansion([true, true, true, true, true]); + assertExpansion([true, true, true, true]); backspaceText(gSearchBox, 1); }, function() { - assertExpansion([true, true, true, true, true]); + assertExpansion([true, true, true, true]); EventUtils.sendKey("RETURN", gDebugger); }, function() { - assertExpansion([true, true, true, true, true]); + assertExpansion([true, true, true, true]); EventUtils.sendKey("RETURN", gDebugger); }, function() { - assertExpansion([true, true, true, true, true]); + assertExpansion([true, true, true, true]); gEditor.focus(); }, function() { - assertExpansion([true, true, true, true, true]); + assertExpansion([true, true, true, true]); localScope.collapse(); withScope.collapse(); functionScope.collapse(); - globalLexicalScope.collapse(); globalScope.collapse(); }, function() { - assertExpansion([false, false, false, false, false]); + assertExpansion([false, false, false, false]); EventUtils.sendKey("RETURN", gDebugger); }, function() { - assertExpansion([false, false, false, false, false]); + assertExpansion([false, false, false, false]); EventUtils.sendKey("RETURN", gDebugger); }, function() { - assertExpansion([false, false, false, false, false]); + assertExpansion([false, false, false, false]); gEditor.focus(); }, function() { - assertExpansion([false, false, false, false, false]); + assertExpansion([false, false, false, false]); clearText(gSearchBox); typeText(gSearchBox, "*"); }, function() { - assertExpansion([true, true, true, true, true]); + assertExpansion([true, true, true, true]); EventUtils.sendKey("RETURN", gDebugger); }, function() { - assertExpansion([true, true, true, true, true]); + assertExpansion([true, true, true, true]); EventUtils.sendKey("RETURN", gDebugger); }, function() { - assertExpansion([true, true, true, true, true]); + assertExpansion([true, true, true, true]); gEditor.focus(); }, function() { - assertExpansion([true, true, true, true, true]); + assertExpansion([true, true, true, true]); backspaceText(gSearchBox, 1); }, function() { - assertExpansion([true, true, true, true, true]); + assertExpansion([true, true, true, true]); EventUtils.sendKey("RETURN", gDebugger); }, function() { - assertExpansion([true, true, true, true, true]); + assertExpansion([true, true, true, true]); EventUtils.sendKey("RETURN", gDebugger); }, function() { - assertExpansion([true, true, true, true, true]); + assertExpansion([true, true, true, true]); gEditor.focus(); }, function() { - assertExpansion([true, true, true, true, true]); + assertExpansion([true, true, true, true]); } ]; @@ -164,12 +162,8 @@ function testVariablesAndPropertiesFiltering() { "The functionScope should " + (aFlags[2] ? "" : "not ") + "be expanded at this point (" + step + ")."); - is(globalLexicalScope.expanded, aFlags[3], - "The globalLexicalScope should " + (aFlags[3] ? "" : "not ") + - "be expanded at this point (" + step + ")."); - - is(globalScope.expanded, aFlags[4], - "The globalScope should " + (aFlags[4] ? "" : "not ") + + is(globalScope.expanded, aFlags[3], + "The globalScope should " + (aFlags[3] ? "" : "not ") + "be expanded at this point (" + step + ")."); step++; @@ -184,8 +178,7 @@ function prepareVariablesAndProperties() { let localScope = gVariables.getScopeAtIndex(0); let withScope = gVariables.getScopeAtIndex(1); let functionScope = gVariables.getScopeAtIndex(2); - let globalLexicalScope = gVariables.getScopeAtIndex(3); - let globalScope = gVariables.getScopeAtIndex(4); + let globalScope = gVariables.getScopeAtIndex(3); is(localScope.expanded, true, "The localScope should be expanded."); @@ -193,8 +186,6 @@ function prepareVariablesAndProperties() { "The withScope should not be expanded yet."); is(functionScope.expanded, false, "The functionScope should not be expanded yet."); - is(globalLexicalScope.expanded, false, - "The globalLexicalScope should not be expanded yet."); is(globalScope.expanded, false, "The globalScope should not be expanded yet."); @@ -207,14 +198,11 @@ function prepareVariablesAndProperties() { "The withScope should now be expanded."); is(functionScope.expanded, true, "The functionScope should now be expanded."); - is(globalLexicalScope.expanded, true, - "The globalLexicalScope should now be expanded."); is(globalScope.expanded, true, "The globalScope should now be expanded."); withScope.collapse(); functionScope.collapse(); - globalLexicalScope.collapse(); globalScope.collapse(); deferred.resolve(); @@ -222,7 +210,6 @@ function prepareVariablesAndProperties() { withScope.expand(); functionScope.expand(); - globalLexicalScope.expand(); globalScope.expand(); return deferred.promise; diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-05.js b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-05.js index b1ee7d217b37..8d24fb300ac4 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-05.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-filter-05.js @@ -43,18 +43,17 @@ function testVariablesAndPropertiesFiltering() { let localScope = gVariables.getScopeAtIndex(0); let withScope = gVariables.getScopeAtIndex(1); let functionScope = gVariables.getScopeAtIndex(2); - let globalLexicalScope = gVariables.getScopeAtIndex(3); - let globalScope = gVariables.getScopeAtIndex(4); + let globalScope = gVariables.getScopeAtIndex(3); let step = 0; let tests = [ function() { - assertScopeExpansion([true, false, false, false, false]); + assertScopeExpansion([true, false, false, false]); typeText(gSearchBox, "*arguments"); }, function() { - assertScopeExpansion([true, true, true, true, true]); - assertVariablesCountAtLeast([0, 0, 1, 0, 0]); + assertScopeExpansion([true, true, true, true]); + assertVariablesCountAtLeast([0, 0, 1, 0]); is(functionScope.target.querySelectorAll(".variables-view-variable:not([unmatched]) > .title > .name")[0].getAttribute("value"), "arguments", "The arguments pseudoarray should be visible."); @@ -64,8 +63,8 @@ function testVariablesAndPropertiesFiltering() { backspaceText(gSearchBox, 6); }, function() { - assertScopeExpansion([true, true, true, true, true]); - assertVariablesCountAtLeast([0, 0, 1, 0, 1]); + assertScopeExpansion([true, true, true, true]); + assertVariablesCountAtLeast([0, 0, 1, 1]); is(functionScope.target.querySelectorAll(".variables-view-variable:not([unmatched]) > .title > .name")[0].getAttribute("value"), "arguments", "The arguments pseudoarray should be visible."); @@ -80,8 +79,8 @@ function testVariablesAndPropertiesFiltering() { backspaceText(gSearchBox, 2); }, function() { - assertScopeExpansion([true, true, true, true, true]); - assertVariablesCountAtLeast([0, 1, 3, 0, 1]); + assertScopeExpansion([true, true, true, true]); + assertVariablesCountAtLeast([0, 1, 3, 1]); is(functionScope.target.querySelectorAll(".variables-view-variable:not([unmatched]) > .title > .name")[0].getAttribute("value"), "aNumber", "The aNumber param should be visible."); @@ -101,8 +100,8 @@ function testVariablesAndPropertiesFiltering() { backspaceText(gSearchBox, 1); }, function() { - assertScopeExpansion([true, true, true, true, true]); - assertVariablesCountAtLeast([4, 1, 3, 0, 1]); + assertScopeExpansion([true, true, true, true]); + assertVariablesCountAtLeast([4, 1, 3, 1]); is(localScope.target.querySelectorAll(".variables-view-variable:not([unmatched]) > .title > .name")[0].getAttribute("value"), "this", "The this reference should be visible."); @@ -154,12 +153,8 @@ function testVariablesAndPropertiesFiltering() { "The functionScope should " + (aFlags[2] ? "" : "not ") + "be expanded at this point (" + step + ")."); - is(globalLexicalScope.expanded, aFlags[3], - "The globalLexicalScope should " + (aFlags[3] ? "" : "not ") + - "be expanded at this point (" + step + ")."); - - is(globalScope.expanded, aFlags[4], - "The globalScope should " + (aFlags[4] ? "" : "not ") + + is(globalScope.expanded, aFlags[3], + "The globalScope should " + (aFlags[3] ? "" : "not ") + "be expanded at this point (" + step + ")."); } @@ -176,12 +171,8 @@ function testVariablesAndPropertiesFiltering() { "There should be " + aCounts[2] + " variable displayed in the function scope (" + step + ")."); - ok(globalLexicalScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length >= aCounts[3], + ok(globalScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length >= aCounts[3], "There should be " + aCounts[3] + - " variable displayed in the global scope (" + step + ")."); - - ok(globalScope.target.querySelectorAll(".variables-view-variable:not([unmatched])").length >= aCounts[4], - "There should be " + aCounts[4] + " variable displayed in the global scope (" + step + ")."); step++; @@ -196,8 +187,7 @@ function prepareVariablesAndProperties() { let localScope = gVariables.getScopeAtIndex(0); let withScope = gVariables.getScopeAtIndex(1); let functionScope = gVariables.getScopeAtIndex(2); - let globalLexicalScope = gVariables.getScopeAtIndex(3); - let globalScope = gVariables.getScopeAtIndex(4); + let globalScope = gVariables.getScopeAtIndex(3); is(localScope.expanded, true, "The localScope should be expanded."); @@ -205,8 +195,6 @@ function prepareVariablesAndProperties() { "The withScope should not be expanded yet."); is(functionScope.expanded, false, "The functionScope should not be expanded yet."); - is(globalLexicalScope.expanded, false, - "The globalScope should not be expanded yet."); is(globalScope.expanded, false, "The globalScope should not be expanded yet."); @@ -219,14 +207,11 @@ function prepareVariablesAndProperties() { "The withScope should now be expanded."); is(functionScope.expanded, true, "The functionScope should now be expanded."); - is(globalLexicalScope.expanded, true, - "The globalScope should now be expanded."); is(globalScope.expanded, true, "The globalScope should now be expanded."); withScope.collapse(); functionScope.collapse(); - globalLexicalScope.collapse(); globalScope.collapse(); deferred.resolve(); @@ -234,7 +219,6 @@ function prepareVariablesAndProperties() { withScope.expand(); functionScope.expand(); - globalLexicalScope.expand(); globalScope.expand(); return deferred.promise; diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-frame-parameters-01.js b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-frame-parameters-01.js index f175f933299b..320ee4104d1e 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-frame-parameters-01.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-frame-parameters-01.js @@ -35,35 +35,27 @@ function test() { function initialChecks() { let scopeNodes = gDebugger.document.querySelectorAll(".variables-view-scope"); - is(scopeNodes.length, 3, - "There should be 3 scopes available."); + is(scopeNodes.length, 2, + "There should be 2 scopes available."); ok(scopeNodes[0].querySelector(".name").getAttribute("value").includes("[test]"), "The local scope should be properly identified."); - ok(scopeNodes[1].querySelector(".name").getAttribute("value").includes("Block"), - "The global lexical scope should be properly identified."); - ok(scopeNodes[2].querySelector(".name").getAttribute("value").includes("[Window]"), + ok(scopeNodes[1].querySelector(".name").getAttribute("value").includes("[Window]"), "The global scope should be properly identified."); is(gVariables.getScopeAtIndex(0).target, scopeNodes[0], "getScopeAtIndex(0) didn't return the expected scope."); is(gVariables.getScopeAtIndex(1).target, scopeNodes[1], "getScopeAtIndex(1) didn't return the expected scope."); - is(gVariables.getScopeAtIndex(2).target, scopeNodes[2], - "getScopeAtIndex(2) didn't return the expected scope."); is(gVariables.getItemForNode(scopeNodes[0]).target, scopeNodes[0], "getItemForNode([0]) didn't return the expected scope."); is(gVariables.getItemForNode(scopeNodes[1]).target, scopeNodes[1], "getItemForNode([1]) didn't return the expected scope."); - is(gVariables.getItemForNode(scopeNodes[2]).target, scopeNodes[2], - "getItemForNode([2]) didn't return the expected scope."); is(gVariables.getItemForNode(scopeNodes[0]).expanded, true, "The local scope should be expanded by default."); is(gVariables.getItemForNode(scopeNodes[1]).expanded, false, - "The global lexical scope should not be collapsed by default."); - is(gVariables.getItemForNode(scopeNodes[2]).expanded, false, "The global scope should not be collapsed by default."); } diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-frame-parameters-03.js b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-frame-parameters-03.js index 2866c2ce1900..7b0768138766 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-frame-parameters-03.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-frame-parameters-03.js @@ -38,7 +38,7 @@ function test() { function expandGlobalScope() { let deferred = promise.defer(); - let globalScope = gVariables.getScopeAtIndex(2); + let globalScope = gVariables.getScopeAtIndex(1); is(globalScope.expanded, false, "The global scope should not be expanded by default."); @@ -52,7 +52,7 @@ function expandGlobalScope() { } function testGlobalScope() { - let globalScope = gVariables.getScopeAtIndex(2); + let globalScope = gVariables.getScopeAtIndex(1); is(globalScope.expanded, true, "The global scope should now be expanded."); @@ -92,7 +92,7 @@ function testGlobalScope() { function expandWindowVariable() { let deferred = promise.defer(); - let windowVar = gVariables.getScopeAtIndex(2).get("window"); + let windowVar = gVariables.getScopeAtIndex(1).get("window"); is(windowVar.expanded, false, "The window variable should not be expanded by default."); @@ -106,7 +106,7 @@ function expandWindowVariable() { } function testWindowVariable() { - let windowVar = gVariables.getScopeAtIndex(2).get("window"); + let windowVar = gVariables.getScopeAtIndex(1).get("window"); is(windowVar.expanded, true, "The window variable should now be expanded."); diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-override-01.js b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-override-01.js index 3b7c08977c8f..84391a08fe8e 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-override-01.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-override-01.js @@ -21,13 +21,11 @@ function test() { let firstScope = variables.getScopeAtIndex(0); let secondScope = variables.getScopeAtIndex(1); let thirdScope = variables.getScopeAtIndex(2); - let globalLexicalScope = variables.getScopeAtIndex(3); - let globalScope = variables.getScopeAtIndex(4); + let globalScope = variables.getScopeAtIndex(3); ok(firstScope, "The first scope is available."); ok(secondScope, "The second scope is available."); ok(thirdScope, "The third scope is available."); - ok(globalLexicalScope, "The global lexical scope is available."); ok(globalScope, "The global scope is available."); is(firstScope.name, "Function scope [secondNest]", @@ -36,8 +34,6 @@ function test() { "The second scope's name is correct."); is(thirdScope.name, "Function scope [test]", "The third scope's name is correct."); - is(globalLexicalScope.name, "Block scope", - "The global lexical scope's name is correct."); is(globalScope.name, "Global scope [Window]", "The global scope's name is correct."); @@ -47,8 +43,6 @@ function test() { "The second scope's expansion state is correct."); is(thirdScope.expanded, false, "The third scope's expansion state is correct."); - is(globalLexicalScope.expanded, false, - "The global lexical scope's expansion state is correct."); is(globalScope.expanded, false, "The global scope's expansion state is correct."); @@ -58,8 +52,6 @@ function test() { "The second scope should have no variables available yet."); is(thirdScope._store.size, 0, "The third scope should have no variables available yet."); - is(globalLexicalScope._store.size, 0, - "The global scope should have no variables available yet."); is(globalScope._store.size, 0, "The global scope should have no variables available yet."); @@ -108,7 +100,6 @@ function test() { fetched = waitForDebuggerEvents(panel, events.FETCHED_VARIABLES); secondScope.expand(); thirdScope.expand(); - globalLexicalScope.expand(); globalScope.expand(); yield fetched; diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-16.js b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-16.js index 676878d245cd..4b4e0407e1e0 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-16.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-popup-16.js @@ -42,7 +42,7 @@ function test() { } function expandGlobalScope() { - let globalScope = variables.getScopeAtIndex(2); + let globalScope = variables.getScopeAtIndex(1); is(globalScope.expanded, false, "The globalScope should not be expanded yet."); diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-reexpand-01.js b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-reexpand-01.js index 70a638e85e50..5beab91342af 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-reexpand-01.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-reexpand-01.js @@ -74,8 +74,7 @@ function testVariablesExpand() { let localScope = gVariables.getScopeAtIndex(0); let withScope = gVariables.getScopeAtIndex(1); let functionScope = gVariables.getScopeAtIndex(2); - let globalLexicalScope = gVariables.getScopeAtIndex(3); - let globalScope = gVariables.getScopeAtIndex(4); + let globalScope = gVariables.getScopeAtIndex(3); let thisVar = localScope.get("this"); let windowVar = thisVar.get("window"); @@ -86,8 +85,6 @@ function testVariablesExpand() { "The withScope arrow should still be expanded."); is(functionScope.target.querySelector(".arrow").hasAttribute("open"), true, "The functionScope arrow should still be expanded."); - is(globalLexicalScope.target.querySelector(".arrow").hasAttribute("open"), true, - "The globalLexicalScope arrow should still be expanded."); is(globalScope.target.querySelector(".arrow").hasAttribute("open"), true, "The globalScope arrow should still be expanded."); is(thisVar.target.querySelector(".arrow").hasAttribute("open"), true, @@ -101,8 +98,6 @@ function testVariablesExpand() { "The withScope enumerables should still be expanded."); is(functionScope.target.querySelector(".variables-view-element-details").hasAttribute("open"), true, "The functionScope enumerables should still be expanded."); - is(globalLexicalScope.target.querySelector(".variables-view-element-details").hasAttribute("open"), true, - "The globalLexicalScope enumerables should still be expanded."); is(globalScope.target.querySelector(".variables-view-element-details").hasAttribute("open"), true, "The globalScope enumerables should still be expanded."); is(thisVar.target.querySelector(".variables-view-element-details").hasAttribute("open"), true, @@ -116,8 +111,6 @@ function testVariablesExpand() { "The withScope expanded getter should return true."); is(functionScope.expanded, true, "The functionScope expanded getter should return true."); - is(globalLexicalScope.expanded, true, - "The globalScope expanded getter should return true."); is(globalScope.expanded, true, "The globalScope expanded getter should return true."); is(thisVar.expanded, true, @@ -132,8 +125,7 @@ function prepareVariablesAndProperties() { let localScope = gVariables.getScopeAtIndex(0); let withScope = gVariables.getScopeAtIndex(1); let functionScope = gVariables.getScopeAtIndex(2); - let globalLexicalScope = gVariables.getScopeAtIndex(3); - let globalScope = gVariables.getScopeAtIndex(4); + let globalScope = gVariables.getScopeAtIndex(3); is(localScope.expanded, true, "The localScope should be expanded."); @@ -141,8 +133,6 @@ function prepareVariablesAndProperties() { "The withScope should not be expanded yet."); is(functionScope.expanded, false, "The functionScope should not be expanded yet."); - is(globalLexicalScope.expanded, false, - "The globalLexicalScope should not be expanded yet."); is(globalScope.expanded, false, "The globalScope should not be expanded yet."); @@ -155,8 +145,6 @@ function prepareVariablesAndProperties() { "The withScope should now be expanded."); is(functionScope.expanded, true, "The functionScope should now be expanded."); - is(globalLexicalScope.expanded, true, - "The globalLexicalScope should now be expanded."); is(globalScope.expanded, true, "The globalScope should now be expanded."); @@ -198,7 +186,6 @@ function prepareVariablesAndProperties() { withScope.expand(); functionScope.expand(); - globalLexicalScope.expand(); globalScope.expand(); return deferred.promise; diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-reexpand-02.js b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-reexpand-02.js index 4da9046db63d..67e0abe843ce 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-reexpand-02.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-reexpand-02.js @@ -75,8 +75,7 @@ function testVariablesExpand() { let localScope = gVariables.getScopeAtIndex(0); let withScope = gVariables.getScopeAtIndex(1); let functionScope = gVariables.getScopeAtIndex(2); - let globalLexicalScope = gVariables.getScopeAtIndex(3); - let globalScope = gVariables.getScopeAtIndex(4); + let globalScope = gVariables.getScopeAtIndex(3); let thisVar = localScope.get("this"); let windowVar = thisVar.get("window"); @@ -89,8 +88,6 @@ function testVariablesExpand() { "The withScope arrow should still be expanded."); is(functionScope.target.querySelector(".arrow").hasAttribute("open"), true, "The functionScope arrow should still be expanded."); - is(globalLexicalScope.target.querySelector(".arrow").hasAttribute("open"), true, - "The globalLexicalScope arrow should still be expanded."); is(globalScope.target.querySelector(".arrow").hasAttribute("open"), true, "The globalScope arrow should still be expanded."); is(thisVar.target.querySelector(".arrow").hasAttribute("open"), true, @@ -108,8 +105,6 @@ function testVariablesExpand() { "The withScope enumerables should still be expanded."); is(functionScope.target.querySelector(".variables-view-element-details").hasAttribute("open"), true, "The functionScope enumerables should still be expanded."); - is(globalLexicalScope.target.querySelector(".variables-view-element-details").hasAttribute("open"), true, - "The globalLexicalScope enumerables should still be expanded."); is(globalScope.target.querySelector(".variables-view-element-details").hasAttribute("open"), true, "The globalScope enumerables should still be expanded."); is(thisVar.target.querySelector(".variables-view-element-details").hasAttribute("open"), true, @@ -127,8 +122,6 @@ function testVariablesExpand() { "The withScope expanded getter should return true."); is(functionScope.expanded, true, "The functionScope expanded getter should return true."); - is(globalLexicalScope.expanded, true, - "The globalLexicalScope expanded getter should return true."); is(globalScope.expanded, true, "The globalScope expanded getter should return true."); is(thisVar.expanded, true, @@ -147,8 +140,7 @@ function prepareVariablesAndProperties() { let localScope = gVariables.getScopeAtIndex(0); let withScope = gVariables.getScopeAtIndex(1); let functionScope = gVariables.getScopeAtIndex(2); - let globalLexicalScope = gVariables.getScopeAtIndex(3); - let globalScope = gVariables.getScopeAtIndex(4); + let globalScope = gVariables.getScopeAtIndex(3); is(localScope.expanded, true, "The localScope should be expanded."); @@ -156,8 +148,6 @@ function prepareVariablesAndProperties() { "The withScope should not be expanded yet."); is(functionScope.expanded, false, "The functionScope should not be expanded yet."); - is(globalLexicalScope.expanded, false, - "The globalLexicalScope should not be expanded yet."); is(globalScope.expanded, false, "The globalScope should not be expanded yet."); @@ -170,8 +160,6 @@ function prepareVariablesAndProperties() { "The withScope should now be expanded."); is(functionScope.expanded, true, "The functionScope should now be expanded."); - is(globalLexicalScope.expanded, true, - "The globalLexicalScope should now be expanded."); is(globalScope.expanded, true, "The globalScope should now be expanded."); @@ -213,7 +201,6 @@ function prepareVariablesAndProperties() { withScope.expand(); functionScope.expand(); - globalLexicalScope.expand(); globalScope.expand(); return deferred.promise; diff --git a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-webidl.js b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-webidl.js index f21c78e41c11..4988755bf1b4 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-webidl.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-webidl.js @@ -36,7 +36,7 @@ function test() { function expandGlobalScope() { let deferred = promise.defer(); - let globalScope = gVariables.getScopeAtIndex(2); + let globalScope = gVariables.getScopeAtIndex(1); is(globalScope.expanded, false, "The global scope should not be expanded by default."); @@ -51,7 +51,7 @@ function expandGlobalScope() { function performTest() { let deferred = promise.defer(); - let globalScope = gVariables.getScopeAtIndex(2); + let globalScope = gVariables.getScopeAtIndex(1); let buttonVar = globalScope.get("button"); let buttonAsProtoVar = globalScope.get("buttonAsProto"); diff --git a/devtools/client/debugger/test/mochitest/doc_function-search.html b/devtools/client/debugger/test/mochitest/doc_function-search.html index eb0e7eaeae9d..711a873edb73 100644 --- a/devtools/client/debugger/test/mochitest/doc_function-search.html +++ b/devtools/client/debugger/test/mochitest/doc_function-search.html @@ -17,10 +17,10 @@