diff --git a/CLOBBER b/CLOBBER index 8675373cfacf..05f0acb5cdfd 100644 --- a/CLOBBER +++ b/CLOBBER @@ -22,4 +22,4 @@ # changes to stick? As of bug 928195, this shouldn't be necessary! Please # don't change CLOBBER for WebIDL changes any more. -Bug 1351604 - required because DER.jsm and X509.jsm are no longer shipped with the browser +Bug 1351074 - required because bug 1352982 means removing a .jsm requires a clobber diff --git a/browser/base/content/test/general/contextmenu_common.js b/browser/base/content/test/general/contextmenu_common.js index 97878a40e5d7..18e27c5afd8f 100644 --- a/browser/base/content/test/general/contextmenu_common.js +++ b/browser/base/content/test/general/contextmenu_common.js @@ -17,7 +17,9 @@ function openContextMenuFor(element, shiftkey, waitForSpellCheck) { } if (waitForSpellCheck) { - var { onSpellCheck } = SpecialPowers.Cu.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm", {}); + var { onSpellCheck } = + SpecialPowers.Cu.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm", {}); onSpellCheck(element, actuallyOpenContextMenuFor); } else { actuallyOpenContextMenuFor(); @@ -278,7 +280,9 @@ function* test_contextmenu(selector, menuItems, options = {}) { if (options.waitForSpellCheck) { info("Waiting for spell check"); yield ContentTask.spawn(gBrowser.selectedBrowser, selector, function*(contentSelector) { - let {onSpellCheck} = Cu.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm", {}); + let {onSpellCheck} = + Cu.import("resource://testing-common/AsyncSpellCheckTestHelper.jsm", + {}); let element = content.document.querySelector(contentSelector); yield new Promise(resolve => onSpellCheck(element, resolve)); info("Spell check running"); diff --git a/browser/base/content/test/static/browser_all_files_referenced.js b/browser/base/content/test/static/browser_all_files_referenced.js index 7be8a510b287..50ffe6643135 100644 --- a/browser/base/content/test/static/browser_all_files_referenced.js +++ b/browser/base/content/test/static/browser_all_files_referenced.js @@ -231,8 +231,6 @@ var whitelist = new Set([ {file: "resource://gre-resources/checkmark.svg"}, {file: "resource://gre-resources/indeterminate-checkmark.svg"}, {file: "resource://gre-resources/radio.svg"}, - // Bug 1351074 - {file: "resource://gre/modules/AsyncSpellCheckTestHelper.jsm"}, // Bug 1351078 {file: "resource://gre/modules/Battery.jsm"}, // Bug 1351070 diff --git a/browser/base/content/test/static/browser_parsable_css.js b/browser/base/content/test/static/browser_parsable_css.js index 02279fd61b0d..21178109e9c0 100644 --- a/browser/base/content/test/static/browser_parsable_css.js +++ b/browser/base/content/test/static/browser_parsable_css.js @@ -39,9 +39,24 @@ let whitelist = [ errorMessage: /Unknown property.*-moz-/i, isFromDevTools: false}, // Reserved to UA sheets unless layout.css.overflow-clip-box.enabled flipped to true. - {sourceName: /res\/forms\.css$/i, + {sourceName: /(?:res|gre-resources)\/forms\.css$/i, errorMessage: /Unknown property.*overflow-clip-box/i, isFromDevTools: false}, + // These variables are declared somewhere else, and error when we load the + // files directly. They're all marked intermittent because their appearance + // in the error console seems to not be consistent. + {sourceName: /jsonview\/css\/general\.css$/i, + intermittent: true, + errorMessage: /Property contained reference to invalid variable.*color/i, + isFromDevTools: true}, + {sourceName: /webide\/skin\/logs\.css$/i, + intermittent: true, + errorMessage: /Property contained reference to invalid variable.*color/i, + isFromDevTools: true}, + {sourceName: /devtools\/skin\/animationinspector\.css$/i, + intermittent: true, + errorMessage: /Property contained reference to invalid variable.*color/i, + isFromDevTools: true}, ]; if (!Services.prefs.getBoolPref("full-screen-api.unprefix.enabled")) { @@ -93,20 +108,20 @@ function ignoredError(aErrorObject) { return false; } -function once(target, name) { - return new Promise((resolve, reject) => { - let cb = () => { - target.removeEventListener(name, cb); - resolve(); - }; - target.addEventListener(name, cb); - }); -} - var gChromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"] .getService(Ci.nsIChromeRegistry); var gChromeMap = new Map(); +var resHandler = Services.io.getProtocolHandler("resource") + .QueryInterface(Ci.nsIResProtocolHandler); +var gResourceMap = []; +function trackResourcePrefix(prefix) { + let uri = Services.io.newURI("resource://" + prefix + "/"); + gResourceMap.unshift([prefix, resHandler.resolveURI(uri)]); +} +trackResourcePrefix("gre"); +trackResourcePrefix("app"); + function getBaseUriForChromeUri(chromeUri) { let chromeFile = chromeUri + "gobbledygooknonexistentfile.reallynothere"; let uri = Services.io.newURI(chromeFile); @@ -118,35 +133,34 @@ function parseManifest(manifestUri) { return fetchFile(manifestUri.spec).then(data => { for (let line of data.split("\n")) { let [type, ...argv] = line.split(/\s+/); - let component; if (type == "content" || type == "skin") { - [component] = argv; - } else { - // skip unrelated lines - continue; + let chromeUri = `chrome://${argv[0]}/${type}/`; + gChromeMap.set(getBaseUriForChromeUri(chromeUri), chromeUri); + } else if (type == "resource") { + trackResourcePrefix(argv[0]); } - let chromeUri = `chrome://${component}/${type}/`; - gChromeMap.set(getBaseUriForChromeUri(chromeUri), chromeUri); } }); } -function convertToChromeUri(fileUri) { - let baseUri = fileUri.spec; +function convertToCodeURI(fileUri) { + let baseUri = fileUri; let path = ""; while (true) { let slashPos = baseUri.lastIndexOf("/", baseUri.length - 2); - if (slashPos < 0) { - info(`File not accessible from chrome protocol: ${fileUri.path}`); + if (slashPos <= 0) { + // File not accessible from chrome protocol, try resource:// + for (let res of gResourceMap) { + if (fileUri.startsWith(res[1])) + return fileUri.replace(res[1], "resource://" + res[0] + "/"); + } + // Give up and return the original URL. return fileUri; } path = baseUri.slice(slashPos + 1) + path; baseUri = baseUri.slice(0, slashPos + 1); - if (gChromeMap.has(baseUri)) { - let chromeBaseUri = gChromeMap.get(baseUri); - let chromeUri = `${chromeBaseUri}${path}`; - return Services.io.newURI(chromeUri); - } + if (gChromeMap.has(baseUri)) + return gChromeMap.get(baseUri) + path; } } @@ -235,10 +249,12 @@ add_task(function* checkAllTheCSS() { // Create a clean iframe to load all the files into. This needs to live at a // chrome URI so that it's allowed to load and parse any styles. let testFile = getRootDirectory(gTestPath) + "dummy_page.html"; - let windowless = Services.appShell.createWindowlessBrowser(); - let iframe = windowless.document.createElementNS("http://www.w3.org/1999/xhtml", "html:iframe"); - windowless.document.documentElement.appendChild(iframe); - let iframeLoaded = once(iframe, "load"); + let HiddenFrame = Cu.import("resource:///modules/HiddenFrame.jsm", {}).HiddenFrame; + let hiddenFrame = new HiddenFrame(); + let win = yield hiddenFrame.get(); + let iframe = win.document.createElementNS("http://www.w3.org/1999/xhtml", "html:iframe"); + win.document.documentElement.appendChild(iframe); + let iframeLoaded = BrowserTestUtils.waitForEvent(iframe, "load", true); iframe.contentWindow.location = testFile; yield iframeLoaded; let doc = iframe.contentWindow.document; @@ -285,8 +301,8 @@ add_task(function* checkAllTheCSS() { linkEl.addEventListener("load", onLoad); linkEl.addEventListener("error", onError); linkEl.setAttribute("type", "text/css"); - let chromeUri = convertToChromeUri(uri); - linkEl.setAttribute("href", chromeUri.spec + kPathSuffix); + let chromeUri = convertToCodeURI(uri.spec); + linkEl.setAttribute("href", chromeUri + kPathSuffix); })); doc.head.appendChild(linkEl); } @@ -322,7 +338,7 @@ add_task(function* checkAllTheCSS() { // Confirm that all whitelist rules have been used. for (let item of whitelist) { - if (!item.used && isDevtools == item.isFromDevTools) { + if (!item.used && isDevtools == item.isFromDevTools && !item.intermittent) { ok(false, "Unused whitelist item. " + (item.sourceName ? " sourceName: " + item.sourceName : "") + (item.errorMessage ? " errorMessage: " + item.errorMessage : "")); @@ -344,7 +360,8 @@ add_task(function* checkAllTheCSS() { doc.head.innerHTML = ""; doc = null; iframe = null; - windowless.close(); - windowless = null; + win = null; + hiddenFrame.destroy(); + hiddenFrame = null; imageURIsToReferencesMap = null; }); diff --git a/browser/components/migration/SafariProfileMigrator.js b/browser/components/migration/SafariProfileMigrator.js index 628e4305d9b3..1a20b9354740 100644 --- a/browser/components/migration/SafariProfileMigrator.js +++ b/browser/components/migration/SafariProfileMigrator.js @@ -179,7 +179,7 @@ Bookmarks.prototype = { return { url, title }; } return null; - }).filter(e => !!e); + }, this).filter(e => !!e); }, }; diff --git a/browser/components/migration/tests/unit/Library/Safari/Bookmarks.plist b/browser/components/migration/tests/unit/Library/Safari/Bookmarks.plist index 40783c7b1501..8046d5e9c984 100644 Binary files a/browser/components/migration/tests/unit/Library/Safari/Bookmarks.plist and b/browser/components/migration/tests/unit/Library/Safari/Bookmarks.plist differ diff --git a/browser/components/migration/tests/unit/test_Safari_bookmarks.js b/browser/components/migration/tests/unit/test_Safari_bookmarks.js index edc32dc72f83..b142f2453990 100644 --- a/browser/components/migration/tests/unit/test_Safari_bookmarks.js +++ b/browser/components/migration/tests/unit/test_Safari_bookmarks.js @@ -15,11 +15,15 @@ add_task(function* () { let expectedParents = [ PlacesUtils.toolbarFolderId ]; let itemCount = 0; + let gotFolder = false; let bmObserver = { onItemAdded(aItemId, aParentId, aIndex, aItemType, aURI, aTitle) { if (aTitle != label) { itemCount++; } + if (aItemType == PlacesUtils.bookmarks.TYPE_FOLDER && aTitle == "Stuff") { + gotFolder = true; + } if (expectedParents.length > 0 && aTitle == label) { let index = expectedParents.indexOf(aParentId); Assert.ok(index != -1, "Found expected parent"); @@ -40,6 +44,7 @@ add_task(function* () { // Check the bookmarks have been imported to all the expected parents. Assert.ok(!expectedParents.length, "No more expected parents"); + Assert.ok(gotFolder, "Should have seen the folder get imported"); Assert.equal(itemCount, 13, "Should import all 13 items."); // Check that the telemetry matches: Assert.equal(MigrationUtils._importQuantities.bookmarks, itemCount, "Telemetry reporting correct."); diff --git a/caps/nsScriptSecurityManager.cpp b/caps/nsScriptSecurityManager.cpp index 59c24902b55d..9db0ee2a7f25 100644 --- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -898,6 +898,23 @@ nsScriptSecurityManager::CheckLoadURIFlags(nsIURI *aSourceURI, } } + static bool sCanLoadChromeInContent = false; + static bool sCachedCanLoadChromeInContentPref = false; + if (!sCachedCanLoadChromeInContentPref) { + sCachedCanLoadChromeInContentPref = true; + mozilla::Preferences::AddBoolVarCache(&sCanLoadChromeInContent, + "security.allow_chrome_frames_inside_content"); + } + if (sCanLoadChromeInContent) { + // Special-case the hidden window: it's allowed to load + // URI_IS_UI_RESOURCE no matter what. Bug 1145470 tracks removing this. + nsAutoCString sourceSpec; + if (NS_SUCCEEDED(aSourceBaseURI->GetSpec(sourceSpec)) && + sourceSpec.EqualsLiteral("resource://gre-resources/hiddenWindow.html")) { + return NS_OK; + } + } + if (reportErrors) { ReportError(nullptr, errorTag, aSourceURI, aTargetURI); } diff --git a/dom/media/gmp/GMPServiceChild.cpp b/dom/media/gmp/GMPServiceChild.cpp index acbc5807cd35..81edd4d3a708 100644 --- a/dom/media/gmp/GMPServiceChild.cpp +++ b/dom/media/gmp/GMPServiceChild.cpp @@ -293,6 +293,13 @@ GeckoMediaPluginServiceChild::UpdateGMPCapabilities(nsTArray& } } +void +GeckoMediaPluginServiceChild::BeginShutdown() +{ + MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread); + mShuttingDownOnGMPThread = true; +} + NS_IMETHODIMP GeckoMediaPluginServiceChild::HasPluginForAPI(const nsACString& aAPI, nsTArray* aTags, @@ -374,6 +381,13 @@ GeckoMediaPluginServiceChild::GetServiceChild() MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread); if (!mServiceChild) { + if (mShuttingDownOnGMPThread) { + // We have begun shutdown. Don't allow a new connection to the main + // process to be instantiated. This also prevents new plugins being + // instantiated. + return GetServiceChildPromise::CreateAndReject(NS_ERROR_FAILURE, + __func__); + } dom::ContentChild* contentChild = dom::ContentChild::GetSingleton(); if (!contentChild) { return GetServiceChildPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); @@ -411,6 +425,9 @@ GeckoMediaPluginServiceChild::RemoveGMPContentParent(GMPContentParent* aGMPConte if (mServiceChild) { mServiceChild->RemoveGMPContentParent(aGMPContentParent); + if (mShuttingDownOnGMPThread && !mServiceChild->HaveContentParents()) { + mServiceChild = nullptr; + } } } @@ -515,5 +532,23 @@ GMPServiceChild::Create(Endpoint&& aGMPService) return NS_SUCCEEDED(rv); } +ipc::IPCResult +GMPServiceChild::RecvBeginShutdown() +{ + RefPtr service = + GeckoMediaPluginServiceChild::GetSingleton(); + MOZ_ASSERT(service && service->mServiceChild.get() == this); + if (service) { + service->BeginShutdown(); + } + return IPC_OK(); +} + +bool +GMPServiceChild::HaveContentParents() const +{ + return mContentParents.Count() > 0; +} + } // namespace gmp } // namespace mozilla diff --git a/dom/media/gmp/GMPServiceChild.h b/dom/media/gmp/GMPServiceChild.h index 02d1dcf821ef..26acdf80e807 100644 --- a/dom/media/gmp/GMPServiceChild.h +++ b/dom/media/gmp/GMPServiceChild.h @@ -42,6 +42,8 @@ public: static void UpdateGMPCapabilities(nsTArray&& aCapabilities); + void BeginShutdown(); + protected: void InitializePlugins(AbstractThread*) override { @@ -85,6 +87,10 @@ public: static bool Create(Endpoint&& aGMPService); + ipc::IPCResult RecvBeginShutdown() override; + + bool HaveContentParents() const; + private: nsRefPtrHashtable mContentParents; }; diff --git a/dom/media/gmp/GMPServiceParent.cpp b/dom/media/gmp/GMPServiceParent.cpp index 94d0f2241d1b..36c79297cd14 100644 --- a/dom/media/gmp/GMPServiceParent.cpp +++ b/dom/media/gmp/GMPServiceParent.cpp @@ -93,7 +93,6 @@ GeckoMediaPluginServiceParent::GeckoMediaPluginServiceParent() , mWaitingForPluginsSyncShutdown(false) , mInitPromiseMonitor("GeckoMediaPluginServiceParent::mInitPromiseMonitor") , mLoadPluginsFromDiskComplete(false) - , mServiceUserCount(0) , mMainThread(SystemGroup::AbstractMainThreadFor(TaskCategory::Other)) { MOZ_ASSERT(NS_IsMainThread()); @@ -469,6 +468,10 @@ GeckoMediaPluginServiceParent::UnloadPlugins() // Move all plugins references to a local array. This way mMutex won't be // locked when calling CloseActive (to avoid inter-locking). Swap(plugins, mPlugins); + + for (GMPServiceParent* parent : mServiceParents) { + Unused << parent->SendBeginShutdown(); + } } LOGD(("%s::%s plugins:%" PRIuSIZE, __CLASS__, __FUNCTION__, @@ -1632,10 +1635,14 @@ GeckoMediaPluginServiceParent::BlockShutdown(nsIAsyncShutdownClient*) } void -GeckoMediaPluginServiceParent::ServiceUserCreated() +GeckoMediaPluginServiceParent::ServiceUserCreated( + GMPServiceParent* aServiceParent) { - MOZ_ASSERT(mServiceUserCount >= 0); - if (++mServiceUserCount == 1) { + MOZ_ASSERT(NS_IsMainThread()); + MutexAutoLock lock(mMutex); + MOZ_ASSERT(!mServiceParents.Contains(aServiceParent)); + mServiceParents.AppendElement(aServiceParent); + if (mServiceParents.Length() == 1) { nsresult rv = GetShutdownBarrier()->AddBlocker( this, NS_LITERAL_STRING(__FILE__), __LINE__, NS_LITERAL_STRING("GeckoMediaPluginServiceParent shutdown")); @@ -1644,10 +1651,15 @@ GeckoMediaPluginServiceParent::ServiceUserCreated() } void -GeckoMediaPluginServiceParent::ServiceUserDestroyed() +GeckoMediaPluginServiceParent::ServiceUserDestroyed( + GMPServiceParent* aServiceParent) { - MOZ_ASSERT(mServiceUserCount > 0); - if (--mServiceUserCount == 0) { + MOZ_ASSERT(NS_IsMainThread()); + MutexAutoLock lock(mMutex); + MOZ_ASSERT(mServiceParents.Length() > 0); + MOZ_ASSERT(mServiceParents.Contains(aServiceParent)); + mServiceParents.RemoveElement(aServiceParent); + if (mServiceParents.IsEmpty()) { nsresult rv = GetShutdownBarrier()->RemoveBlocker(this); MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); } @@ -1692,12 +1704,17 @@ GeckoMediaPluginServiceParent::GetById(uint32_t aPluginId) return nullptr; } +GMPServiceParent::GMPServiceParent(GeckoMediaPluginServiceParent* aService) + : mService(aService) +{ + MOZ_ASSERT(mService); + mService->ServiceUserCreated(this); +} + GMPServiceParent::~GMPServiceParent() { - nsCOMPtr task = NewRunnableMethod( - "GeckoMediaPluginServiceParent::ServiceUserDestroyed", - mService.get(), &GeckoMediaPluginServiceParent::ServiceUserDestroyed); - mService->MainThread()->Dispatch(task.forget()); + MOZ_ASSERT(mService); + mService->ServiceUserDestroyed(this); } mozilla::ipc::IPCResult @@ -1850,7 +1867,16 @@ GMPServiceParent::ActorDestroy(ActorDestroyReason aWhy) lock.Wait(); } - NS_DispatchToCurrentThread(new DeleteGMPServiceParent(this)); + // Dispatch a task to the current thread to ensure we don't delete the + // GMPServiceParent until the current calling context is finished with + // the object. + GMPServiceParent* self = this; + NS_DispatchToCurrentThread(NS_NewRunnableFunction([self]() { + // The GMPServiceParent must be destroyed on the main thread. + NS_DispatchToMainThread(NS_NewRunnableFunction([self]() { + delete self; + })); + })); } class OpenPGMPServiceParent : public mozilla::Runnable diff --git a/dom/media/gmp/GMPServiceParent.h b/dom/media/gmp/GMPServiceParent.h index 9e468e39840a..86a0a8d5cf16 100644 --- a/dom/media/gmp/GMPServiceParent.h +++ b/dom/media/gmp/GMPServiceParent.h @@ -23,6 +23,7 @@ namespace mozilla { namespace gmp { class GMPParent; +class GMPServiceParent; class GeckoMediaPluginServiceParent final : public GeckoMediaPluginService , public mozIGeckoMediaPluginChromeService @@ -60,8 +61,8 @@ public: const mozilla::OriginAttributesPattern& aPattern); // Notifies that some user of this class is created/destroyed. - void ServiceUserCreated(); - void ServiceUserDestroyed(); + void ServiceUserCreated(GMPServiceParent* aServiceParent); + void ServiceUserDestroyed(GMPServiceParent* aServiceParent); void UpdateContentProcessGMPCapabilities(); @@ -207,9 +208,10 @@ private: // Hashes nodeId to the hashtable of storage for that nodeId. nsRefPtrHashtable mTempGMPStorage; - // Tracks how many users are running (on the GMP thread). Only when this count - // drops to 0 can we safely shut down the thread. - MainThreadOnly mServiceUserCount; + // Tracks how many IPC connections to GMPServices running in content + // processes we have. When this is empty we can safely shut down. + // Synchronized across thread via mMutex in base class. + nsTArray mServiceParents; const RefPtr mMainThread; }; @@ -222,11 +224,7 @@ bool MatchOrigin(nsIFile* aPath, class GMPServiceParent final : public PGMPServiceParent { public: - explicit GMPServiceParent(GeckoMediaPluginServiceParent* aService) - : mService(aService) - { - mService->ServiceUserCreated(); - } + explicit GMPServiceParent(GeckoMediaPluginServiceParent* aService); virtual ~GMPServiceParent(); ipc::IPCResult RecvGetGMPNodeId(const nsString& aOrigin, diff --git a/dom/media/gmp/PGMPService.ipdl b/dom/media/gmp/PGMPService.ipdl index c09547a05071..a8ed27d1f32e 100644 --- a/dom/media/gmp/PGMPService.ipdl +++ b/dom/media/gmp/PGMPService.ipdl @@ -36,6 +36,8 @@ parent: sync GetGMPNodeId(nsString origin, nsString topLevelOrigin, nsString gmpName) returns (nsCString id); +child: + async BeginShutdown(); }; } // namespace gmp diff --git a/editor/composer/test/test_async_UpdateCurrentDictionary.html b/editor/composer/test/test_async_UpdateCurrentDictionary.html index 11189ba96add..c7724e83e415 100644 --- a/editor/composer/test/test_async_UpdateCurrentDictionary.html +++ b/editor/composer/test/test_async_UpdateCurrentDictionary.html @@ -24,7 +24,8 @@ function start() { var textarea = document.getElementById("editor"); textarea.focus(); - SpecialPowers.Cu.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm") + SpecialPowers.Cu.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm") .onSpellCheck(textarea, function () { var isc = SpecialPowers.wrap(textarea).editor.getInlineSpellChecker(false); ok(isc, "Inline spell checker should exist after focus and spell check"); diff --git a/editor/composer/test/test_bug1200533.html b/editor/composer/test/test_bug1200533.html index 198850e9cb6e..d9326e858103 100644 --- a/editor/composer/test/test_bug1200533.html +++ b/editor/composer/test/test_bug1200533.html @@ -101,7 +101,8 @@ function continueTest(evt) { editor.setSpellcheckUserOverride(true); var inlineSpellChecker = editor.getInlineSpellChecker(true); - SpecialPowers.Cu.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm") + SpecialPowers.Cu.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm") .onSpellCheck(elem, function () { var spellchecker = inlineSpellChecker.spellChecker; try { diff --git a/editor/composer/test/test_bug1204147.html b/editor/composer/test/test_bug1204147.html index 1e33d71a352e..a30c42995595 100644 --- a/editor/composer/test/test_bug1204147.html +++ b/editor/composer/test/test_bug1204147.html @@ -67,7 +67,8 @@ var loadListener = function(evt) { editor.setSpellcheckUserOverride(true); var inlineSpellChecker = editor.getInlineSpellChecker(true); - SpecialPowers.Cu.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm") + SpecialPowers.Cu.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm") .onSpellCheck(elem, function () { var spellchecker = inlineSpellChecker.spellChecker; try { diff --git a/editor/composer/test/test_bug1205983.html b/editor/composer/test/test_bug1205983.html index 139f6fc3c59a..f13150c35c66 100644 --- a/editor/composer/test/test_bug1205983.html +++ b/editor/composer/test/test_bug1205983.html @@ -29,8 +29,8 @@ var selcon_de; var script; var onSpellCheck = - SpecialPowers.Cu.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm") - .onSpellCheck; + SpecialPowers.Cu.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm").onSpellCheck; /** Test for Bug 1205983 **/ SimpleTest.waitForExplicitFinish(); diff --git a/editor/composer/test/test_bug1209414.html b/editor/composer/test/test_bug1209414.html index 4c7858061ef4..77bc3214c582 100644 --- a/editor/composer/test/test_bug1209414.html +++ b/editor/composer/test/test_bug1209414.html @@ -37,8 +37,8 @@ var script; */ var onSpellCheck = - SpecialPowers.Cu.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm") - .onSpellCheck; + SpecialPowers.Cu.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm").onSpellCheck; SimpleTest.waitForExplicitFinish(); SimpleTest.waitForFocus(function() { diff --git a/editor/composer/test/test_bug1219928.html b/editor/composer/test/test_bug1219928.html index 2f646f00f3ff..4a4c05c7e7fc 100644 --- a/editor/composer/test/test_bug1219928.html +++ b/editor/composer/test/test_bug1219928.html @@ -29,8 +29,8 @@ var spellchecker; SimpleTest.waitForExplicitFinish(); SimpleTest.waitForFocus(function() { - SpecialPowers.Cu.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm", - window); + SpecialPowers.Cu.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm", window); var elem = document.getElementById('en-US'); elem.focus(); diff --git a/editor/composer/test/test_bug338427.html b/editor/composer/test/test_bug338427.html index f16194b3d39b..392ec5184209 100644 --- a/editor/composer/test/test_bug338427.html +++ b/editor/composer/test/test_bug338427.html @@ -21,7 +21,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=338427 /** Test for Bug 338427 **/ function init() { var onSpellCheck = - SpecialPowers.Cu.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm") + SpecialPowers.Cu.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm") .onSpellCheck; var textarea = document.getElementById("editor"); var editor = SpecialPowers.wrap(textarea).editor; diff --git a/editor/composer/test/test_bug678842.html b/editor/composer/test/test_bug678842.html index 9fc0b2cf9fa9..69e1626e64dc 100644 --- a/editor/composer/test/test_bug678842.html +++ b/editor/composer/test/test_bug678842.html @@ -60,7 +60,8 @@ var loadListener = function(evt) { editor.setSpellcheckUserOverride(true); var inlineSpellChecker = editor.getInlineSpellChecker(true); - SpecialPowers.Cu.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm") + SpecialPowers.Cu.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm") .onSpellCheck(elem, function () { var spellchecker = inlineSpellChecker.spellChecker; try { diff --git a/editor/composer/test/test_bug697981.html b/editor/composer/test/test_bug697981.html index f9417acb050a..e455d8dd81d6 100644 --- a/editor/composer/test/test_bug697981.html +++ b/editor/composer/test/test_bug697981.html @@ -28,7 +28,8 @@ var editor_de; var script; var onSpellCheck = - SpecialPowers.Cu.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm") + SpecialPowers.Cu.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm") .onSpellCheck; /** Test for Bug 697981 **/ diff --git a/editor/composer/test/test_bug717433.html b/editor/composer/test/test_bug717433.html index adb17842ed3f..6318a7e44e3e 100644 --- a/editor/composer/test/test_bug717433.html +++ b/editor/composer/test/test_bug717433.html @@ -62,7 +62,8 @@ var loadListener = function(evt) { editor.setSpellcheckUserOverride(true); var inlineSpellChecker = editor.getInlineSpellChecker(true); - SpecialPowers.Cu.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm") + SpecialPowers.Cu.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm") .onSpellCheck(elem, function () { var spellchecker = inlineSpellChecker.spellChecker; try { diff --git a/editor/libeditor/tests/test_bug366682.html b/editor/libeditor/tests/test_bug366682.html index bac618941a74..18e4a7eea419 100644 --- a/editor/libeditor/tests/test_bug366682.html +++ b/editor/libeditor/tests/test_bug366682.html @@ -49,7 +49,8 @@ function runTest() { gMisspeltWords = ["errror", "errror"]; editDoc().designMode = "on"; - SpecialPowers.Cu.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm") + SpecialPowers.Cu.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm") .onSpellCheck(editDoc().documentElement, evalTest); } diff --git a/editor/libeditor/tests/test_bug484181.html b/editor/libeditor/tests/test_bug484181.html index 55cd8e80662e..81ffa6418ef7 100644 --- a/editor/libeditor/tests/test_bug484181.html +++ b/editor/libeditor/tests/test_bug484181.html @@ -53,7 +53,8 @@ function runTest() { var edit = document.getElementById("edit"); edit.focus(); - SpecialPowers.Cu.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm", window); + SpecialPowers.Cu.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm", window); onSpellCheck(edit, function () { ok(isSpellingCheckOk(getEditor(), gMisspeltWords), "All misspellings before editing are accounted for."); diff --git a/editor/libeditor/tests/test_bug596333.html b/editor/libeditor/tests/test_bug596333.html index a94726325624..49ce1f3e1fc0 100644 --- a/editor/libeditor/tests/test_bug596333.html +++ b/editor/libeditor/tests/test_bug596333.html @@ -112,7 +112,8 @@ function runTest() var edit = document.getElementById("edit"); edit.focus(); - SpecialPowers.Cu.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm", window); + SpecialPowers.Cu.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm", window); onSpellCheck(edit, runOnFocus); } diff --git a/editor/libeditor/tests/test_bug636465.html b/editor/libeditor/tests/test_bug636465.html index 37ceebe5a2f2..6a884582e867 100644 --- a/editor/libeditor/tests/test_bug636465.html +++ b/editor/libeditor/tests/test_bug636465.html @@ -11,8 +11,8 @@ SimpleTest.waitForExplicitFinish(); function runTest() { - SpecialPowers.Cu.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm", - window); + SpecialPowers.Cu.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm", window); var x = document.getElementById("x"); x.focus(); onSpellCheck(x, function () { diff --git a/editor/moz.build b/editor/moz.build index 690c891abe7c..35185341b907 100644 --- a/editor/moz.build +++ b/editor/moz.build @@ -38,7 +38,7 @@ EXPORTS += [ 'nsEditorCID.h', ] -EXTRA_JS_MODULES += [ +TESTING_JS_MODULES += [ 'AsyncSpellCheckTestHelper.jsm', ] diff --git a/extensions/spellcheck/tests/chrome/test_add_remove_dictionaries.xul b/extensions/spellcheck/tests/chrome/test_add_remove_dictionaries.xul index 661eaccff496..140fb4bd91b6 100644 --- a/extensions/spellcheck/tests/chrome/test_add_remove_dictionaries.xul +++ b/extensions/spellcheck/tests/chrome/test_add_remove_dictionaries.xul @@ -67,7 +67,8 @@ function RunTest() { ok(map.exists()); hunspell.addDirectory(map); - Components.utils.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm"); + Components.utils.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm"); onSpellCheck(textbox, function () { // test that base and map dictionaries are available diff --git a/extensions/spellcheck/tests/mochitest/test_bug1170484.html b/extensions/spellcheck/tests/mochitest/test_bug1170484.html index bdfb39f18f39..91bb0c1ad339 100644 --- a/extensions/spellcheck/tests/mochitest/test_bug1170484.html +++ b/extensions/spellcheck/tests/mochitest/test_bug1170484.html @@ -13,7 +13,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1170484 /** Test for Bug 1170484 **/ SimpleTest.waitForExplicitFinish(); - SpecialPowers.Cu.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm", window); + SpecialPowers.Cu.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm", window); SimpleTest.waitForFocus(doTest, window); function doTest() { diff --git a/extensions/spellcheck/tests/mochitest/test_bug1272623.html b/extensions/spellcheck/tests/mochitest/test_bug1272623.html index b5eeeacb1977..14a0ff357556 100644 --- a/extensions/spellcheck/tests/mochitest/test_bug1272623.html +++ b/extensions/spellcheck/tests/mochitest/test_bug1272623.html @@ -54,7 +54,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1272623 } add_task(function* () { - SpecialPowers.Cu.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm", window); + SpecialPowers.Cu.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm", window); // Wait for the page to be ready yield new Promise(resolve => SimpleTest.waitForFocus(() => SimpleTest.executeSoon(resolve), window)); diff --git a/js/src/gc/Memory.cpp b/js/src/gc/Memory.cpp index 7c632595f7cb..21531adc48d4 100644 --- a/js/src/gc/Memory.cpp +++ b/js/src/gc/Memory.cpp @@ -852,7 +852,7 @@ ProtectPages(void* p, size_t size) #if defined(XP_WIN) DWORD oldProtect; if (!VirtualProtect(p, size, PAGE_NOACCESS, &oldProtect)) { - MOZ_CRASH_UNSAFE_PRINTF("VirtualProtect(PAGE_NOACCESS) failed! Error code: %u", + MOZ_CRASH_UNSAFE_PRINTF("VirtualProtect(PAGE_NOACCESS) failed! Error code: %lu", GetLastError()); } MOZ_ASSERT(oldProtect == PAGE_READWRITE); @@ -871,7 +871,7 @@ MakePagesReadOnly(void* p, size_t size) #if defined(XP_WIN) DWORD oldProtect; if (!VirtualProtect(p, size, PAGE_READONLY, &oldProtect)) { - MOZ_CRASH_UNSAFE_PRINTF("VirtualProtect(PAGE_READONLY) failed! Error code: %u", + MOZ_CRASH_UNSAFE_PRINTF("VirtualProtect(PAGE_READONLY) failed! Error code: %lu", GetLastError()); } MOZ_ASSERT(oldProtect == PAGE_READWRITE); @@ -890,7 +890,7 @@ UnprotectPages(void* p, size_t size) #if defined(XP_WIN) DWORD oldProtect; if (!VirtualProtect(p, size, PAGE_READWRITE, &oldProtect)) { - MOZ_CRASH_UNSAFE_PRINTF("VirtualProtect(PAGE_READWRITE) failed! Error code: %u", + MOZ_CRASH_UNSAFE_PRINTF("VirtualProtect(PAGE_READWRITE) failed! Error code: %lu", GetLastError()); } MOZ_ASSERT(oldProtect == PAGE_NOACCESS || oldProtect == PAGE_READONLY); diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 8471ee491045..505b9ba04698 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -1961,6 +1961,7 @@ IonBuilder::inspectOpcode(JSOp op) return jsop_newobject(); case JSOP_NEWARRAY: + case JSOP_SPREADCALLARRAY: return jsop_newarray(GET_UINT32(pc)); case JSOP_NEWARRAY_COPYONWRITE: @@ -2012,6 +2013,9 @@ IonBuilder::inspectOpcode(JSOp op) case JSOP_FUNAPPLY: return jsop_funapply(GET_ARGC(pc)); + case JSOP_SPREADCALL: + return jsop_spreadcall(); + case JSOP_CALL: case JSOP_CALL_IGNORES_RV: case JSOP_CALLITER: @@ -5050,6 +5054,45 @@ IonBuilder::jsop_funapply(uint32_t argc) return jsop_funapplyarguments(argc); } +AbortReasonOr +IonBuilder::jsop_spreadcall() +{ + // The arguments array is constructed by a JSOP_SPREADCALLARRAY and not + // leaked to user. The complications of spread call iterator behaviour are + // handled when the user objects are expanded and copied into this hidden + // array. + +#ifdef DEBUG + // If we know class, ensure it is what we expected + MDefinition* argument = current->peek(-1); + if (TemporaryTypeSet* objTypes = argument->resultTypeSet()) + if (const Class* clasp = objTypes->getKnownClass(constraints())) + MOZ_ASSERT(clasp == &ArrayObject::class_); +#endif + + MDefinition* argArr = current->pop(); + MDefinition* argThis = current->pop(); + MDefinition* argFunc = current->pop(); + + // Extract call target. + TemporaryTypeSet* funTypes = argFunc->resultTypeSet(); + JSFunction* target = getSingleCallTarget(funTypes); + WrappedFunction* wrappedTarget = target ? new(alloc()) WrappedFunction(target) : nullptr; + + // Dense elements of argument array + MElements* elements = MElements::New(alloc(), argArr); + current->add(elements); + + MApplyArray* apply = MApplyArray::New(alloc(), wrappedTarget, argFunc, elements, argThis); + current->add(apply); + current->push(apply); + MOZ_TRY(resumeAfter(apply)); + + // TypeBarrier the call result + TemporaryTypeSet* types = bytecodeTypes(pc); + return pushTypeBarrier(apply, types, BarrierKind::TypeSet); +} + AbortReasonOr IonBuilder::jsop_funapplyarray(uint32_t argc) { diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index ac6c55a29452..5155b1cb7f37 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -504,6 +504,7 @@ class IonBuilder AbortReasonOr jsop_funapply(uint32_t argc); AbortReasonOr jsop_funapplyarguments(uint32_t argc); AbortReasonOr jsop_funapplyarray(uint32_t argc); + AbortReasonOr jsop_spreadcall(); AbortReasonOr jsop_call(uint32_t argc, bool constructing, bool ignoresReturnValue); AbortReasonOr jsop_eval(uint32_t argc); AbortReasonOr jsop_label(); diff --git a/layout/base/tests/bug512295-1-ref.html b/layout/base/tests/bug512295-1-ref.html index b2f8201c76a9..944cb3d87bf4 100644 --- a/layout/base/tests/bug512295-1-ref.html +++ b/layout/base/tests/bug512295-1-ref.html @@ -12,7 +12,8 @@ x var p = document.getElementById('p'); var div = p.parentNode; div.focus(); - SpecialPowers.Cu.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm", window); + SpecialPowers.Cu.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm", window); onSpellCheck(div, function () { var sel = window.getSelection(); sel.removeAllRanges(); diff --git a/layout/base/tests/bug512295-1.html b/layout/base/tests/bug512295-1.html index b69974d6c13f..64984a3cd831 100644 --- a/layout/base/tests/bug512295-1.html +++ b/layout/base/tests/bug512295-1.html @@ -19,7 +19,8 @@ x sel.addRange(range); p.parentNode.focus(); - SpecialPowers.Cu.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm", window); + SpecialPowers.Cu.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm", window); onSpellCheck(p.parentNode, function () { sendKey('DOWN'); // now after "1" sendKey('DOWN'); // now make sure we get to the end diff --git a/layout/base/tests/bug512295-2-ref.html b/layout/base/tests/bug512295-2-ref.html index dddf935e4a8c..90600c2df727 100644 --- a/layout/base/tests/bug512295-2-ref.html +++ b/layout/base/tests/bug512295-2-ref.html @@ -12,7 +12,8 @@ x var p = document.getElementById('p'); var div = p.parentNode; div.focus(); - SpecialPowers.Cu.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm", window); + SpecialPowers.Cu.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm", window); onSpellCheck(div, function () { var sel = window.getSelection(); sel.removeAllRanges(); diff --git a/layout/base/tests/bug512295-2.html b/layout/base/tests/bug512295-2.html index 3d64c44a615c..fc8c9401058d 100644 --- a/layout/base/tests/bug512295-2.html +++ b/layout/base/tests/bug512295-2.html @@ -19,7 +19,8 @@ x sel.addRange(range); p.parentNode.focus(); - SpecialPowers.Cu.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm", window); + SpecialPowers.Cu.import( + "resource://testing-common/AsyncSpellCheckTestHelper.jsm", window); onSpellCheck(p.parentNode, function () { sendKey('DOWN'); // now after "1" sendKey('DOWN'); // now below the P element diff --git a/layout/base/tests/bug923376-ref.html b/layout/base/tests/bug923376-ref.html index 3a60cf195d93..0ec11f7d0b57 100644 --- a/layout/base/tests/bug923376-ref.html +++ b/layout/base/tests/bug923376-ref.html @@ -3,8 +3,8 @@