diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index 568736b19549..a733fbfc854c 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 4b3490781e2e..27b026f895bc 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 5cb19934eba7..1a87af64f2cf 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 1836c87a2538..c54ef6862690 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 10eac1869dc8..d1e309beb981 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 4b3490781e2e..27b026f895bc 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 3033be36d474..65b915c665be 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/flame/sources.xml b/b2g/config/flame/sources.xml index e0ff847c5886..d38c404f136b 100644 --- a/b2g/config/flame/sources.xml +++ b/b2g/config/flame/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 50e1cf25cc16..75a3ad824ea2 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,9 +1,9 @@ { "git": { - "git_revision": "2fb09da0cb9cefad9c6e40f57533fafda6d12557", + "git_revision": "f6a1fcd30ee6a286f3bca9d0c3cb600e21bfbf69", "remote": "https://git.mozilla.org/releases/gaia.git", "branch": "" }, - "revision": "82758e5ede4ffa620385685078202fcef4e08760", + "revision": "96b7e916f53ebcd185b087338913edb5ffdadade", "repo_path": "integration/gaia-central" } diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index b876a17f33c7..1cf9fe4c5cee 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/nexus-5-l/sources.xml b/b2g/config/nexus-5-l/sources.xml index bc138e3d5baa..20671f976354 100644 --- a/b2g/config/nexus-5-l/sources.xml +++ b/b2g/config/nexus-5-l/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/installer/package-manifest.in b/b2g/installer/package-manifest.in index d35382ee5d8f..b85525308df7 100644 --- a/b2g/installer/package-manifest.in +++ b/b2g/installer/package-manifest.in @@ -69,7 +69,6 @@ @BINPATH@/@DLL_PREFIX@plds4@DLL_SUFFIX@ @BINPATH@/@DLL_PREFIX@nspr4@DLL_SUFFIX@ #endif -@BINPATH@/@DLL_PREFIX@mozalloc@DLL_SUFFIX@ #ifdef MOZ_DMD @BINPATH@/@DLL_PREFIX@dmd@DLL_SUFFIX@ #endif diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index c2e15b6bf51b..459b087d34a2 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1202,9 +1202,14 @@ pref("security.sandbox.windows.log", false); pref("dom.ipc.plugins.sandbox-level.default", 0); #if defined(MOZ_CONTENT_SANDBOX) -// This controls whether the Windows content process sandbox is using a more -// strict sandboxing policy. This will require a restart. -pref("security.sandbox.windows.content.moreStrict", false); +// This controls the strength of the Windows content process sandbox for testing +// purposes. This will require a restart. +// On windows these levels are: +// 0 - sandbox with USER_NON_ADMIN access token level +// 1 - a more strict sandbox, which causes problems in specific areas +// 2 - a policy that we can reasonably call an effective sandbox +// 3 - an equivalent basic policy to the Chromium renderer processes +pref("security.sandbox.content.level", 0); #if defined(MOZ_STACKWALKING) // This controls the depth of stack trace that is logged when Windows sandbox @@ -1225,7 +1230,7 @@ pref("security.sandbox.windows.log.stackTraceDepth", 0); // This setting is read when the content process is started. On Mac the content // process is killed when all windows are closed, so a change will take effect // when the 1st window is opened. -pref("security.sandbox.macos.content.level", 0); +pref("security.sandbox.content.level", 0); #endif // This pref governs whether we attempt to work around problems caused by diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index b3982d04542f..71ef386ab0fe 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -67,7 +67,6 @@ #ifdef GKMEDIAS_SHARED_LIBRARY @BINPATH@/@DLL_PREFIX@gkmedias@DLL_SUFFIX@ #endif -@BINPATH@/@DLL_PREFIX@mozalloc@DLL_SUFFIX@ #ifdef MOZ_SHARED_MOZGLUE @BINPATH@/@DLL_PREFIX@mozglue@DLL_SUFFIX@ #endif diff --git a/build/gecko_templates.mozbuild b/build/gecko_templates.mozbuild index 46ff7d2b456f..f8bbfca3cc43 100644 --- a/build/gecko_templates.mozbuild +++ b/build/gecko_templates.mozbuild @@ -32,12 +32,15 @@ def GeckoBinary(linkage='dependent', msvcrt='dynamic', mozglue=None): xpcomglue = 'xpcomglue_staticruntime' if not CONFIG['GNU_CC']: mozglue = None + if linkage == 'dependent': + USE_LIBS += [ + 'mozalloc_staticruntime', + ] else: error('msvcrt must be "dynamic" or "static"') if linkage == 'dependent': USE_LIBS += [ - 'mozalloc', 'nspr', '%s_s' % xpcomglue, 'xul', diff --git a/dom/base/nsCopySupport.cpp b/dom/base/nsCopySupport.cpp index 8631b94b1c44..436b0f9f5489 100644 --- a/dom/base/nsCopySupport.cpp +++ b/dom/base/nsCopySupport.cpp @@ -50,6 +50,7 @@ #include "mozilla/EventDispatcher.h" #include "mozilla/Preferences.h" #include "mozilla/dom/Selection.h" +#include "mozilla/IntegerRange.h" using namespace mozilla; using namespace mozilla::dom; @@ -148,7 +149,8 @@ SelectionCopyHelper(nsISelection *aSel, nsIDocument *aDoc, nsIDocumentEncoder::OutputAbsoluteLinks | nsIDocumentEncoder::SkipInvisibleContent | nsIDocumentEncoder::OutputDropInvisibleBreak | - (aFlags & nsIDocumentEncoder::OutputNoScriptContent); + (aFlags & (nsIDocumentEncoder::OutputNoScriptContent | + nsIDocumentEncoder::OutputRubyAnnotation)); mimeType.AssignLiteral(kTextMime); rv = docEncoder->Init(domDoc, mimeType, flags); @@ -273,11 +275,13 @@ SelectionCopyHelper(nsISelection *aSel, nsIDocument *aDoc, nsresult nsCopySupport::HTMLCopy(nsISelection* aSel, nsIDocument* aDoc, - int16_t aClipboardID) + int16_t aClipboardID, bool aWithRubyAnnotation) { - return SelectionCopyHelper(aSel, aDoc, true, aClipboardID, - nsIDocumentEncoder::SkipInvisibleContent, - nullptr); + uint32_t flags = nsIDocumentEncoder::SkipInvisibleContent; + if (aWithRubyAnnotation) { + flags |= nsIDocumentEncoder::OutputRubyAnnotation; + } + return SelectionCopyHelper(aSel, aDoc, true, aClipboardID, flags, nullptr); } nsresult @@ -582,6 +586,38 @@ nsCopySupport::CanCopy(nsIDocument* aDocument) return !isCollapsed; } +static bool +IsInsideRuby(nsINode* aNode) +{ + for (; aNode; aNode = aNode->GetParent()) { + if (aNode->IsHTMLElement(nsGkAtoms::ruby)) { + return true; + } + } + return false; +} + +static bool +IsSelectionInsideRuby(nsISelection* aSelection) +{ + int32_t rangeCount; + nsresult rv = aSelection->GetRangeCount(&rangeCount); + if (NS_FAILED(rv)) { + return false; + } + for (auto i : MakeRange(rangeCount)) { + nsCOMPtr range; + aSelection->GetRangeAt(i, getter_AddRefs(range)); + nsCOMPtr node; + range->GetCommonAncestorContainer(getter_AddRefs(node)); + nsCOMPtr n = do_QueryInterface(node); + if (!IsInsideRuby(n)) { + return false; + } + } + return true; +} + bool nsCopySupport::FireClipboardEvent(int32_t aType, int32_t aClipboardType, nsIPresShell* aPresShell, nsISelection* aSelection) { @@ -690,8 +726,13 @@ nsCopySupport::FireClipboardEvent(int32_t aType, int32_t aClipboardType, nsIPres if (isCollapsed) { return false; } + // XXX Code which decides whether we should copy text with ruby + // annotation is currenct depending on whether each range of the + // selection is inside a same ruby container. But we really should + // expose the full functionality in browser. See bug 1130891. + bool withRubyAnnotation = IsSelectionInsideRuby(sel); // call the copy code - rv = HTMLCopy(sel, doc, aClipboardType); + rv = HTMLCopy(sel, doc, aClipboardType, withRubyAnnotation); if (NS_FAILED(rv)) { return false; } diff --git a/dom/base/nsCopySupport.h b/dom/base/nsCopySupport.h index b8db3b48108b..15670a52198d 100644 --- a/dom/base/nsCopySupport.h +++ b/dom/base/nsCopySupport.h @@ -23,7 +23,8 @@ class nsCopySupport { // class of static helper functions for copy support public: - static nsresult HTMLCopy(nsISelection *aSel, nsIDocument *aDoc, int16_t aClipboardID); + static nsresult HTMLCopy(nsISelection *aSel, nsIDocument *aDoc, + int16_t aClipboardID, bool aWithRubyAnnotation); static nsresult DoHooks(nsIDocument *aDoc, nsITransferable *aTrans, bool *aDoPutOnClipboard); diff --git a/dom/base/nsDocumentEncoder.cpp b/dom/base/nsDocumentEncoder.cpp index 44ce139816bb..4021f3c46a2b 100644 --- a/dom/base/nsDocumentEncoder.cpp +++ b/dom/base/nsDocumentEncoder.cpp @@ -124,6 +124,11 @@ protected: // We have already checked that our parent is visible. return true; } + if (aNode->IsHTMLElement(nsGkAtoms::rp)) { + // Ruby parentheses are part of ruby structure, hence + // shouldn't be stripped out even if it is not displayed. + return true; + } return false; } bool isVisible = frame->StyleVisibility()->IsVisible(); diff --git a/dom/base/nsFrameMessageManager.cpp b/dom/base/nsFrameMessageManager.cpp index 0f18550cbd0e..c7dfe8e6b6e5 100644 --- a/dom/base/nsFrameMessageManager.cpp +++ b/dom/base/nsFrameMessageManager.cpp @@ -1956,13 +1956,13 @@ NS_NewParentProcessMessageManager(nsIMessageBroadcaster** aResult) nullptr, MM_CHROME | MM_PROCESSMANAGER | MM_BROADCASTER); nsFrameMessageManager::sParentProcessManager = mm; - nsFrameMessageManager::NewProcessMessageManager(nullptr); // Create same process message manager. + nsFrameMessageManager::NewProcessMessageManager(false); // Create same process message manager. return CallQueryInterface(mm, aResult); } nsFrameMessageManager* -nsFrameMessageManager::NewProcessMessageManager(mozilla::dom::nsIContentParent* aProcess) +nsFrameMessageManager::NewProcessMessageManager(bool aIsRemote) { if (!nsFrameMessageManager::sParentProcessManager) { nsCOMPtr dummy = @@ -1972,8 +1972,10 @@ nsFrameMessageManager::NewProcessMessageManager(mozilla::dom::nsIContentParent* MOZ_ASSERT(nsFrameMessageManager::sParentProcessManager, "parent process manager not created"); nsFrameMessageManager* mm; - if (aProcess) { - mm = new nsFrameMessageManager(aProcess, + if (aIsRemote) { + // Callback is set in ContentParent::InitInternal so that the process has + // already started when we send pending scripts. + mm = new nsFrameMessageManager(nullptr, nsFrameMessageManager::sParentProcessManager, MM_CHROME | MM_PROCESSMANAGER); } else { diff --git a/dom/base/nsFrameMessageManager.h b/dom/base/nsFrameMessageManager.h index 7e2f1dd266fc..37f0ffd92a1e 100644 --- a/dom/base/nsFrameMessageManager.h +++ b/dom/base/nsFrameMessageManager.h @@ -225,7 +225,7 @@ public: NS_DECL_NSIPROCESSCHECKER static nsFrameMessageManager* - NewProcessMessageManager(mozilla::dom::nsIContentParent* aProcess); + NewProcessMessageManager(bool aIsRemote); nsresult ReceiveMessage(nsISupports* aTarget, const nsAString& aMessage, bool aIsSync, const StructuredCloneData* aCloneData, diff --git a/dom/base/nsGkAtomList.h b/dom/base/nsGkAtomList.h index 6eca907de9d8..00abf58db3ee 100644 --- a/dom/base/nsGkAtomList.h +++ b/dom/base/nsGkAtomList.h @@ -826,6 +826,7 @@ GK_ATOM(onpagehide, "onpagehide") GK_ATOM(onpageshow, "onpageshow") GK_ATOM(onpaint, "onpaint") GK_ATOM(onpairedstatuschanged, "onpairedstatuschanged") +GK_ATOM(onpairingaborted, "onpairingaborted") GK_ATOM(onpairingconfirmationreq, "onpairingconfirmationreq") GK_ATOM(onpairingconsentreq, "onpairingconsentreq") GK_ATOM(onpaste, "onpaste") @@ -1014,8 +1015,10 @@ GK_ATOM(round, "round") GK_ATOM(row, "row") GK_ATOM(rows, "rows") GK_ATOM(rowspan, "rowspan") +GK_ATOM(rb, "rb") GK_ATOM(rp, "rp") GK_ATOM(rt, "rt") +GK_ATOM(rtc, "rtc") GK_ATOM(rtl, "rtl") GK_ATOM(ruby, "ruby") GK_ATOM(rubyBase, "ruby-base") diff --git a/dom/base/nsIDocumentEncoder.idl b/dom/base/nsIDocumentEncoder.idl index 155e5c375c6e..f983b87d2d9d 100644 --- a/dom/base/nsIDocumentEncoder.idl +++ b/dom/base/nsIDocumentEncoder.idl @@ -35,7 +35,7 @@ interface nsIDocumentEncoderNodeFixup : nsISupports nsIDOMNode fixupNode(in nsIDOMNode aNode, out boolean aSerializeCloneKids); }; -[scriptable, uuid(1158bd7e-a08b-4ff6-9417-6f99144cfccc)] +[scriptable, uuid(e5ec69d7-eaa7-4de7-986b-455e17c7f71a)] interface nsIDocumentEncoder : nsISupports { // Output methods flag bits. There are a frightening number of these, @@ -234,6 +234,12 @@ interface nsIDocumentEncoder : nsISupports */ const unsigned long OutputForPlainTextClipboardCopy = (1 << 25); + /** + * Include ruby annotations and ruby parentheses in the output. + * PlainText output only. + */ + const unsigned long OutputRubyAnnotation = (1 << 26); + /** * Initialize with a pointer to the document and the mime type. * @param aDocument Document to encode. diff --git a/dom/base/nsPlainTextSerializer.cpp b/dom/base/nsPlainTextSerializer.cpp index 875520ec271f..b9db9c7d268e 100644 --- a/dom/base/nsPlainTextSerializer.cpp +++ b/dom/base/nsPlainTextSerializer.cpp @@ -29,6 +29,7 @@ using namespace mozilla::dom; #define PREF_STRUCTS "converter.html2txt.structs" #define PREF_HEADER_STRATEGY "converter.html2txt.header_strategy" +#define PREF_ALWAYS_INCLUDE_RUBY "converter.html2txt.always_include_ruby" static const int32_t kTabSize=4; static const int32_t kIndentSizeHeaders = 2; /* Indention of h1, if @@ -92,6 +93,7 @@ nsPlainTextSerializer::nsPlainTextSerializer() mStartedOutput = false; mPreformattedBlockBoundary = false; + mWithRubyAnnotation = false; // will be read from pref and flag later // initialize the tag stack to zero: // The stack only ever contains pointers to static atoms, so they don't @@ -188,6 +190,13 @@ nsPlainTextSerializer::Init(uint32_t aFlags, uint32_t aWrapColumn, } } + // The pref is default inited to false in libpref, but we use true + // as fallback value because we don't want to affect behavior in + // other places which use this serializer currently. + mWithRubyAnnotation = + Preferences::GetBool(PREF_ALWAYS_INCLUDE_RUBY, true) || + (mFlags & nsIDocumentEncoder::OutputRubyAnnotation); + // XXX We should let the caller decide whether to do this or not mFlags &= ~nsIDocumentEncoder::OutputNoFramesContent; @@ -255,6 +264,19 @@ nsPlainTextSerializer::ShouldReplaceContainerWithPlaceholder(nsIAtom* aTag) (aTag == nsGkAtoms::video); } +bool +nsPlainTextSerializer::IsIgnorableRubyAnnotation(nsIAtom* aTag) +{ + if (mWithRubyAnnotation) { + return false; + } + + return + aTag == nsGkAtoms::rp || + aTag == nsGkAtoms::rt || + aTag == nsGkAtoms::rtc; +} + NS_IMETHODIMP nsPlainTextSerializer::AppendText(nsIContent* aText, int32_t aStartOffset, @@ -440,6 +462,12 @@ nsPlainTextSerializer::DoOpenContainer(nsIAtom* aTag) mIgnoredChildNodeLevel++; return NS_OK; } + if (IsIgnorableRubyAnnotation(aTag)) { + // Ignorable ruby annotation shouldn't be replaced by a placeholder + // character, neither any of its descendants. + mIgnoredChildNodeLevel++; + return NS_OK; + } if (mFlags & nsIDocumentEncoder::OutputForPlainTextClipboardCopy) { if (mPreformattedBlockBoundary && DoOutput()) { @@ -780,6 +808,10 @@ nsPlainTextSerializer::DoCloseContainer(nsIAtom* aTag) mIgnoredChildNodeLevel--; return NS_OK; } + if (IsIgnorableRubyAnnotation(aTag)) { + mIgnoredChildNodeLevel--; + return NS_OK; + } if (mFlags & nsIDocumentEncoder::OutputForPlainTextClipboardCopy) { if (DoOutput() && IsInPre() && IsElementBlock(mElement)) { diff --git a/dom/base/nsPlainTextSerializer.h b/dom/base/nsPlainTextSerializer.h index bb8347a60ddd..9d0f3e700879 100644 --- a/dom/base/nsPlainTextSerializer.h +++ b/dom/base/nsPlainTextSerializer.h @@ -113,6 +113,7 @@ private: bool PopBool(nsTArray& aStack); bool ShouldReplaceContainerWithPlaceholder(nsIAtom* aTag); + bool IsIgnorableRubyAnnotation(nsIAtom* aTag); bool IsElementPreformatted(mozilla::dom::Element* aElement); bool IsElementBlock(mozilla::dom::Element* aElement); @@ -175,6 +176,9 @@ private: bool mPreformattedBlockBoundary; + // Whether the output should include ruby annotations. + bool mWithRubyAnnotation; + nsString mURL; int32_t mHeaderStrategy; /* Header strategy (pref) 0 = no indention diff --git a/dom/base/nsTreeSanitizer.cpp b/dom/base/nsTreeSanitizer.cpp index 5b4a36b042d8..721107c0ff20 100644 --- a/dom/base/nsTreeSanitizer.cpp +++ b/dom/base/nsTreeSanitizer.cpp @@ -106,8 +106,10 @@ nsIAtom** const kElementsHTML[] = { &nsGkAtoms::pre, &nsGkAtoms::progress, &nsGkAtoms::q, + &nsGkAtoms::rb, &nsGkAtoms::rp, &nsGkAtoms::rt, + &nsGkAtoms::rtc, &nsGkAtoms::ruby, &nsGkAtoms::s, &nsGkAtoms::samp, diff --git a/dom/base/test/browser_messagemanager_loadprocessscript.js b/dom/base/test/browser_messagemanager_loadprocessscript.js index f0c35cb0984b..fa2214d81cb6 100644 --- a/dom/base/test/browser_messagemanager_loadprocessscript.js +++ b/dom/base/test/browser_messagemanager_loadprocessscript.js @@ -18,27 +18,72 @@ function processScript() { }); sendSyncMessage("ProcessTest:Loaded"); } +let processScriptURL = "data:,(" + processScript.toString() + ")()"; -function test() { - waitForExplicitFinish(); +let checkProcess = Task.async(function*(mm) { + let { target } = yield promiseMessage(mm, "ProcessTest:Loaded"); + target.sendAsyncMessage("ProcessTest:Reply"); + yield promiseMessage(target, "ProcessTest:Finished"); + ok(true, "Saw process finished"); +}); - let replyCount = 0; +function promiseMessage(messageManager, message) { + return new Promise(resolve => { + let listener = (msg) => { + messageManager.removeMessageListener(message, listener); + resolve(msg); + }; - function loadListener(msg) { - replyCount++; - msg.target.sendAsyncMessage("ProcessTest:Reply"); - } - - ppmm.addMessageListener("ProcessTest:Loaded", loadListener); - ppmm.addMessageListener("ProcessTest:Finished", function finishListener(msg) { - if (replyCount < ppmm.childCount) { - return; - } - info("Got " + replyCount + " replies"); - ok(replyCount, "Got message reply"); - ppmm.removeMessageListener("ProcessTest:Loaded", loadListener); - ppmm.removeMessageListener("ProcessTest:Finished", finishListener); - finish(); - }); - ppmm.loadProcessScript("data:,(" + processScript.toString() + ")()", true); + messageManager.addMessageListener(message, listener); + }) } + +// Test that loading a process script loads in all existing processes +add_task(function*() { + let checks = []; + for (let i = 0; i < ppmm.childCount; i++) + checks.push(checkProcess(ppmm.getChildAt(i))); + + ppmm.loadProcessScript(processScriptURL, false); + yield Promise.all(checks); +}); + +// Test that loading a process script loads in new processes +add_task(function*() { + // This test is only relevant in e10s + if (!gMultiProcessBrowser) + return; + + is(ppmm.childCount, 2, "Should be two processes at this point"); + + // Load something in the main process + gBrowser.selectedBrowser.loadURI("about:robots"); + yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); + + // With no remote frames left we should be down to one process. + // However, stuff like remote thumbnails can cause a content + // process to exist nonetheless. This should be rare, though, + // so the test is useful most of the time. + if (ppmm.childCount == 1) { + let check = checkProcess(ppmm); + ppmm.loadProcessScript(processScriptURL, true); + + // The main process should respond + yield check; + + check = checkProcess(ppmm); + // Reset the default browser to start a new child process + gBrowser.updateBrowserRemoteness(gBrowser.selectedBrowser, true); + gBrowser.selectedBrowser.loadURI("about:blank"); + yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); + + is(ppmm.childCount, 2, "Should be back to two processes at this point"); + + // The new process should have responded + yield check; + + ppmm.removeDelayedProcessScript(processScriptURL); + } else { + info("Unable to finish test entirely"); + } +}); diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini index c9abd049ef56..f5a79ef24990 100644 --- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -424,7 +424,6 @@ support-files = test_bug357450.js [test_bug380418.html] support-files = test_bug380418.html^headers^ [test_bug382113.html] -skip-if = (os == 'mac' || os == 'win') && debug # bug 453969 [test_bug382871.html] [test_bug384003.xhtml] [test_bug390219.html] diff --git a/dom/base/test/test_bug382113.html b/dom/base/test/test_bug382113.html index 177efd1e3886..3cf6791520cd 100644 --- a/dom/base/test/test_bug382113.html +++ b/dom/base/test/test_bug382113.html @@ -7,6 +7,19 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=382113 Test for Bug 382113 + Mozilla Bug 382113 @@ -16,22 +29,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=382113 onload="objectGotOnload = true;">
-
-
-
-
 
diff --git a/dom/bluetooth2/BluetoothAdapter.cpp b/dom/bluetooth2/BluetoothAdapter.cpp index dbd9511d1274..ca192e212179 100644 --- a/dom/bluetooth2/BluetoothAdapter.cpp +++ b/dom/bluetooth2/BluetoothAdapter.cpp @@ -364,15 +364,9 @@ BluetoothAdapter::Notify(const BluetoothSignal& aData) nsRefPtr event = BluetoothStatusChangedEvent::Constructor(this, aData.name(), init); DispatchTrustedEvent(event); - } else if (aData.name().EqualsLiteral(REQUEST_MEDIA_PLAYSTATUS_ID)) { - nsCOMPtr event; - nsresult rv = NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr); - NS_ENSURE_SUCCESS_VOID(rv); - - rv = event->InitEvent(aData.name(), false, false); - NS_ENSURE_SUCCESS_VOID(rv); - - DispatchTrustedEvent(event); + } else if (aData.name().EqualsLiteral(PAIRING_ABORTED_ID) || + aData.name().EqualsLiteral(REQUEST_MEDIA_PLAYSTATUS_ID)) { + DispatchEmptyEvent(aData.name()); } else { BT_WARNING("Not handling adapter signal: %s", NS_ConvertUTF16toUTF8(aData.name()).get()); @@ -856,30 +850,6 @@ BluetoothAdapter::HandleDeviceFound(const BluetoothValue& aValue) mDiscoveryHandleInUse->DispatchDeviceEvent(discoveredDevice); } -void -BluetoothAdapter::DispatchAttributeEvent(const nsTArray& aTypes) -{ - NS_ENSURE_TRUE_VOID(aTypes.Length()); - - AutoJSAPI jsapi; - NS_ENSURE_TRUE_VOID(jsapi.Init(GetOwner())); - JSContext* cx = jsapi.cx(); - JS::Rooted value(cx); - - if (!ToJSValue(cx, aTypes, &value)) { - JS_ClearPendingException(cx); - return; - } - - RootedDictionary init(cx); - init.mAttrs = value; - nsRefPtr event = - BluetoothAttributeEvent::Constructor(this, - NS_LITERAL_STRING("attributechanged"), - init); - DispatchTrustedEvent(event); -} - void BluetoothAdapter::HandleDevicePaired(const BluetoothValue& aValue) { @@ -951,6 +921,30 @@ BluetoothAdapter::HandleDeviceUnpaired(const BluetoothValue& aValue) DispatchDeviceEvent(NS_LITERAL_STRING("deviceunpaired"), init); } +void +BluetoothAdapter::DispatchAttributeEvent(const nsTArray& aTypes) +{ + NS_ENSURE_TRUE_VOID(aTypes.Length()); + + AutoJSAPI jsapi; + NS_ENSURE_TRUE_VOID(jsapi.Init(GetOwner())); + JSContext* cx = jsapi.cx(); + JS::Rooted value(cx); + + if (!ToJSValue(cx, aTypes, &value)) { + JS_ClearPendingException(cx); + return; + } + + RootedDictionary init(cx); + init.mAttrs = value; + nsRefPtr event = + BluetoothAttributeEvent::Constructor(this, + NS_LITERAL_STRING("attributechanged"), + init); + DispatchTrustedEvent(event); +} + void BluetoothAdapter::DispatchDeviceEvent(const nsAString& aType, const BluetoothDeviceEventInit& aInit) @@ -962,6 +956,19 @@ BluetoothAdapter::DispatchDeviceEvent(const nsAString& aType, DispatchTrustedEvent(event); } +void +BluetoothAdapter::DispatchEmptyEvent(const nsAString& aType) +{ + nsCOMPtr event; + nsresult rv = NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr); + NS_ENSURE_SUCCESS_VOID(rv); + + rv = event->InitEvent(aType, false, false); + NS_ENSURE_SUCCESS_VOID(rv); + + DispatchTrustedEvent(event); +} + already_AddRefed BluetoothAdapter::Connect(BluetoothDevice& aDevice, const Optional& aServiceUuid, diff --git a/dom/bluetooth2/BluetoothAdapter.h b/dom/bluetooth2/BluetoothAdapter.h index 5c65ede7702a..a06555a98581 100644 --- a/dom/bluetooth2/BluetoothAdapter.h +++ b/dom/bluetooth2/BluetoothAdapter.h @@ -83,6 +83,7 @@ public: IMPL_EVENT_HANDLER(attributechanged); IMPL_EVENT_HANDLER(devicepaired); IMPL_EVENT_HANDLER(deviceunpaired); + IMPL_EVENT_HANDLER(pairingaborted); IMPL_EVENT_HANDLER(a2dpstatuschanged); IMPL_EVENT_HANDLER(hfpstatuschanged); IMPL_EVENT_HANDLER(requestmediaplaystatus); @@ -221,6 +222,13 @@ private: */ void HandlePropertyChanged(const BluetoothValue& aValue); + /** + * Handle "DeviceFound" bluetooth signal. + * + * @param aValue [in] Properties array of the discovered device. + */ + void HandleDeviceFound(const BluetoothValue& aValue); + /** * Handle DEVICE_PAIRED_ID bluetooth signal. * @@ -241,13 +249,6 @@ private: */ void HandleDeviceUnpaired(const BluetoothValue& aValue); - /** - * Handle "DeviceFound" bluetooth signal. - * - * @param aValue [in] Properties array of the discovered device. - */ - void HandleDeviceFound(const BluetoothValue& aValue); - /** * Fire BluetoothAttributeEvent to trigger onattributechanged event handler. */ @@ -263,6 +264,13 @@ private: void DispatchDeviceEvent(const nsAString& aType, const BluetoothDeviceEventInit& aInit); + /** + * Fire event with no argument + * + * @param aType [in] Event type to fire + */ + void DispatchEmptyEvent(const nsAString& aType); + /** * Convert string to BluetoothAdapterAttribute. * diff --git a/dom/bluetooth2/BluetoothCommon.h b/dom/bluetooth2/BluetoothCommon.h index d2945b3579e7..816e4f5a4cc6 100644 --- a/dom/bluetooth2/BluetoothCommon.h +++ b/dom/bluetooth2/BluetoothCommon.h @@ -192,11 +192,12 @@ extern bool gBluetoothDebugFlag; #define BLUETOOTH_APP_ORIGIN "app://bluetooth.gaiamobile.org" /** - * When a remote device gets paired / unpaired with local bluetooth adapter, - * we'll dispatch an event. + * When a remote device gets paired / unpaired with local bluetooth adapter or + * pairing process is aborted, we'll dispatch an event. */ #define DEVICE_PAIRED_ID "devicepaired" #define DEVICE_UNPAIRED_ID "deviceunpaired" +#define PAIRING_ABORTED_ID "pairingaborted" /** * When receiving a query about current play status from remote device, we'll diff --git a/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp b/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp index 8e1c1494e564..b536a77d2807 100644 --- a/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp +++ b/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp @@ -1593,74 +1593,76 @@ BluetoothServiceBluedroid::BondStateChangedNotification( return; } - bool bonded = (aState == BOND_STATE_BONDED); + BT_LOGR("Bond state: %d status: %d", aState, aStatus); - // Update bonded address array - nsString remoteBdAddr = nsString(aRemoteBdAddr); - if (bonded) { - if (!sAdapterBondedAddressArray.Contains(remoteBdAddr)) { - sAdapterBondedAddressArray.AppendElement(remoteBdAddr); + bool bonded = (aState == BOND_STATE_BONDED); + if (aStatus != STATUS_SUCCESS) { + if (!bonded) { // Active/passive pair failed + BT_LOGR("Pair failed! Abort pairing."); + + // Notify adapter of pairing aborted + DistributeSignal(NS_LITERAL_STRING(PAIRING_ABORTED_ID), + NS_LITERAL_STRING(KEY_ADAPTER)); + + // Reject pair promise + if (!sBondingRunnableArray.IsEmpty()) { + DispatchReplyError(sBondingRunnableArray[0], aStatus); + sBondingRunnableArray.RemoveElementAt(0); + } + } else if (!sUnbondingRunnableArray.IsEmpty()) { // Active unpair failed + // Reject unpair promise + DispatchReplyError(sUnbondingRunnableArray[0], aStatus); + sUnbondingRunnableArray.RemoveElementAt(0); } - } else { - sAdapterBondedAddressArray.RemoveElement(remoteBdAddr); + + return; } - // Update attribute BluetoothDevice.paired - InfallibleTArray propertiesArray; - BT_APPEND_NAMED_VALUE(propertiesArray, "Paired", bonded); - - // Retrieve device name from hash table of pairing device name. - nsString deviceName = EmptyString(); + // Retrieve and remove pairing device name from hash table + nsString deviceName; bool nameExists = sPairingNameTable.Get(aRemoteBdAddr, &deviceName); if (nameExists) { sPairingNameTable.Remove(aRemoteBdAddr); } - // Update attribute BluetoothDevice.name if the device is paired. - if (bonded && aStatus == STATUS_SUCCESS) { - MOZ_ASSERT(nameExists); + // Update bonded address array and append pairing device name + InfallibleTArray propertiesArray; + nsString remoteBdAddr = nsString(aRemoteBdAddr); + if (!bonded) { + sAdapterBondedAddressArray.RemoveElement(remoteBdAddr); + } else { + if (!sAdapterBondedAddressArray.Contains(remoteBdAddr)) { + sAdapterBondedAddressArray.AppendElement(remoteBdAddr); + } - // We don't assert |!deviceName.IsEmpty()| here since empty string is also - // a valid name. - // According to Bluetooth Core Spec. v3.0 - Sec. 6.22, a valid Bluetooth - // name is a UTF-8 encoding string which is up to 248 bytes in length. + // We don't assert |!deviceName.IsEmpty()| here since empty string is + // also a valid name. According to Bluetooth Core Spec. v3.0 - Sec. 6.22, + // "a valid Bluetooth name is a UTF-8 encoding string which is up to 248 + // bytes in length." + MOZ_ASSERT(nameExists); BT_APPEND_NAMED_VALUE(propertiesArray, "Name", deviceName); } + // Notify device of attribute changed + BT_APPEND_NAMED_VALUE(propertiesArray, "Paired", bonded); DistributeSignal(NS_LITERAL_STRING("PropertyChanged"), aRemoteBdAddr, BluetoothValue(propertiesArray)); - // Insert address to signal properties and notify adapter. - BT_INSERT_NAMED_VALUE(propertiesArray, 0, "Address", nsString(aRemoteBdAddr)); - - nsString signalName = bonded ? NS_LITERAL_STRING(DEVICE_PAIRED_ID) - : NS_LITERAL_STRING(DEVICE_UNPAIRED_ID); - - DistributeSignal(signalName, + // Notify adapter of device paired/unpaired + BT_INSERT_NAMED_VALUE(propertiesArray, 0, "Address", remoteBdAddr); + DistributeSignal(bonded ? NS_LITERAL_STRING(DEVICE_PAIRED_ID) + : NS_LITERAL_STRING(DEVICE_UNPAIRED_ID), NS_LITERAL_STRING(KEY_ADAPTER), BluetoothValue(propertiesArray)); - if (aStatus == STATUS_SUCCESS) { - // Resolve existing pair/unpair promise when pair/unpair succeeded - if (bonded && !sBondingRunnableArray.IsEmpty()) { - DispatchReplySuccess(sBondingRunnableArray[0]); - sBondingRunnableArray.RemoveElementAt(0); - } else if (!bonded && !sUnbondingRunnableArray.IsEmpty()) { - DispatchReplySuccess(sUnbondingRunnableArray[0]); - sUnbondingRunnableArray.RemoveElementAt(0); - } - } else { - // Reject existing pair/unpair promise when pair/unpair failed - if (!bonded && !sBondingRunnableArray.IsEmpty()) { - DispatchReplyError(sBondingRunnableArray[0], - NS_LITERAL_STRING("Pair failed")); - sBondingRunnableArray.RemoveElementAt(0); - } else if (bonded && !sUnbondingRunnableArray.IsEmpty()) { - DispatchReplyError(sUnbondingRunnableArray[0], - NS_LITERAL_STRING("Unpair failed")); - sUnbondingRunnableArray.RemoveElementAt(0); - } + // Resolve existing pair/unpair promise + if (bonded && !sBondingRunnableArray.IsEmpty()) { + DispatchReplySuccess(sBondingRunnableArray[0]); + sBondingRunnableArray.RemoveElementAt(0); + } else if (!bonded && !sUnbondingRunnableArray.IsEmpty()) { + DispatchReplySuccess(sUnbondingRunnableArray[0]); + sUnbondingRunnableArray.RemoveElementAt(0); } } diff --git a/dom/ipc/ContentBridgeParent.cpp b/dom/ipc/ContentBridgeParent.cpp index c787b6fbf9cb..856d68ffcaf3 100644 --- a/dom/ipc/ContentBridgeParent.cpp +++ b/dom/ipc/ContentBridgeParent.cpp @@ -48,6 +48,11 @@ ContentBridgeParent::Create(Transport* aTransport, ProcessId aOtherProcess) DebugOnly ok = bridge->Open(aTransport, handle, XRE_GetIOMessageLoop()); MOZ_ASSERT(ok); + + // Initialize the message manager (and load delayed scripts) now that we + // have established communications with the child. + bridge->mMessageManager->InitWithCallback(bridge); + return bridge.get(); } diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 8e76c1ff3126..e9a8f43b687d 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -1065,8 +1065,10 @@ SetUpSandboxEnvironment() void ContentChild::CleanUpSandboxEnvironment() { - // Sandbox environment is only currently set up with the more strict sandbox. - if (!Preferences::GetBool("security.sandbox.windows.content.moreStrict")) { + // Sandbox environment is only currently a low integrity temp, which only + // makes sense for sandbox pref level 1 (and will eventually not be needed + // at all, once all file access is via chrome/broker process). + if (Preferences::GetInt("security.sandbox.content.level") != 1) { return; } @@ -1207,7 +1209,10 @@ ContentChild::RecvSetProcessSandbox() SetContentProcessSandbox(); #elif defined(XP_WIN) mozilla::SandboxTarget::Instance()->StartSandbox(); - if (Preferences::GetBool("security.sandbox.windows.content.moreStrict")) { + // Sandbox environment is only currently a low integrity temp, which only + // makes sense for sandbox pref level 1 (and will eventually not be needed + // at all, once all file access is via chrome/broker process). + if (Preferences::GetInt("security.sandbox.content.level") == 1) { SetUpSandboxEnvironment(); } #elif defined(XP_MACOSX) diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index f3d94c442639..d1b8f0daf783 100755 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -2286,6 +2286,10 @@ ContentParent::InitInternal(ProcessPriority aInitialPriority, bool aSetupOffMainThreadCompositing, bool aSendRegisteredChrome) { + // Initialize the message manager (and load delayed scripts) now that we + // have established communications with the child. + mMessageManager->InitWithCallback(this); + // Set the subprocess's priority. We do this early on because we're likely // /lowering/ the process's CPU and memory priority, which it has inherited // from this process. diff --git a/dom/ipc/nsIContentParent.cpp b/dom/ipc/nsIContentParent.cpp index f62b5807b0f5..01a5685150ef 100644 --- a/dom/ipc/nsIContentParent.cpp +++ b/dom/ipc/nsIContentParent.cpp @@ -36,7 +36,7 @@ namespace dom { nsIContentParent::nsIContentParent() { - mMessageManager = nsFrameMessageManager::NewProcessMessageManager(this); + mMessageManager = nsFrameMessageManager::NewProcessMessageManager(true); } ContentParent* diff --git a/dom/media/webrtc/MediaEngineCameraVideoSource.h b/dom/media/webrtc/MediaEngineCameraVideoSource.h index f54ab50833ac..afc72c576f14 100644 --- a/dom/media/webrtc/MediaEngineCameraVideoSource.h +++ b/dom/media/webrtc/MediaEngineCameraVideoSource.h @@ -98,7 +98,7 @@ protected: // All the mMonitor accesses are from the child classes. Monitor mMonitor; // Monitor for processing Camera frames. - nsTArray mSources; // When this goes empty, we shut down HW + nsTArray> mSources; // When this goes empty, we shut down HW nsRefPtr mImage; nsRefPtr mImageContainer; int mWidth, mHeight; // protected with mMonitor on Gonk due to different threading diff --git a/dom/media/webrtc/MediaEngineWebRTC.h b/dom/media/webrtc/MediaEngineWebRTC.h index 160b134bd646..e39a194a3fb5 100644 --- a/dom/media/webrtc/MediaEngineWebRTC.h +++ b/dom/media/webrtc/MediaEngineWebRTC.h @@ -219,7 +219,7 @@ private: // from kStarted to kStopped (which are combined with EndTrack()). // mSources[] is accessed from webrtc threads. Monitor mMonitor; - nsTArray mSources; // When this goes empty, we shut down HW + nsTArray> mSources; // When this goes empty, we shut down HW nsCOMPtr mThread; int mCapIndex; int mChannel; diff --git a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp index 8e8dd6c2df24..8342f355374e 100644 --- a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp +++ b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp @@ -585,7 +585,7 @@ MediaEngineWebRTCAudioSource::Process(int channel, if (mSources[i]) { // Make sure we include the stream and the track. // The 0:1 is a flag to note when we've done the final insert for a given input block. - LogTime(AsyncLatencyLogger::AudioTrackInsertion, LATENCY_STREAM_ID(mSources[i], mTrackID), + LogTime(AsyncLatencyLogger::AudioTrackInsertion, LATENCY_STREAM_ID(mSources[i].get(), mTrackID), (i+1 < len) ? 0 : 1, insertTime); // This is safe from any thread, and is safe if the track is Finished diff --git a/dom/plugins/base/nsPluginPlayPreviewInfo.cpp b/dom/plugins/base/nsPluginPlayPreviewInfo.cpp index fea976aa352f..c2a4ae18ed79 100644 --- a/dom/plugins/base/nsPluginPlayPreviewInfo.cpp +++ b/dom/plugins/base/nsPluginPlayPreviewInfo.cpp @@ -60,12 +60,13 @@ nsPluginPlayPreviewInfo::GetWhitelist(nsACString& aWhitelist) return NS_OK; } -NS_IMETHODIMP +/* static */ nsresult nsPluginPlayPreviewInfo::CheckWhitelist(const nsACString& aPageURI, const nsACString& aObjectURI, + const nsACString& aWhitelist, bool *_retval) { - if (mWhitelist.Length() == 0) { + if (aWhitelist.Length() == 0) { // Considering empty whitelist as '*' entry. *_retval = true; return NS_OK; @@ -76,8 +77,8 @@ nsPluginPlayPreviewInfo::CheckWhitelist(const nsACString& aPageURI, // where page_url and object_url pattern matches for aPageURI // and aObjectURI, and performs matching as the same time. nsACString::const_iterator start, end; - mWhitelist.BeginReading(start); - mWhitelist.EndReading(end); + aWhitelist.BeginReading(start); + aWhitelist.EndReading(end); nsAutoCString pageURI(aPageURI); nsAutoCString objectURI(aObjectURI); @@ -143,3 +144,11 @@ nsPluginPlayPreviewInfo::CheckWhitelist(const nsACString& aPageURI, *_retval = false; return NS_OK; } + +NS_IMETHODIMP +nsPluginPlayPreviewInfo::CheckWhitelist(const nsACString& aPageURI, + const nsACString& aObjectURI, + bool *_retval) +{ + return CheckWhitelist(aPageURI, aObjectURI, mWhitelist, _retval); +} diff --git a/dom/plugins/base/nsPluginPlayPreviewInfo.h b/dom/plugins/base/nsPluginPlayPreviewInfo.h index bf3b2d0ec832..a28bba593a7b 100644 --- a/dom/plugins/base/nsPluginPlayPreviewInfo.h +++ b/dom/plugins/base/nsPluginPlayPreviewInfo.h @@ -23,6 +23,18 @@ public: const char* aWhitelist); explicit nsPluginPlayPreviewInfo(const nsPluginPlayPreviewInfo* aSource); + /** This function checks aPageURI and aObjectURI against the whitelist + * specified in aWhitelist. This is public static function because this + * whitelist checking code needs to be accessed without any instances of + * nsIPluginPlayPreviewInfo. In particular, the Shumway whitelist is + * obtained directly from prefs and compared using this code for telemetry + * purposes. + */ + static nsresult CheckWhitelist(const nsACString& aPageURI, + const nsACString& aObjectURI, + const nsACString& aWhitelist, + bool *_retval); + nsCString mMimeType; bool mIgnoreCTP; nsCString mRedirectURL; diff --git a/dom/plugins/ipc/PluginInstanceParent.cpp b/dom/plugins/ipc/PluginInstanceParent.cpp index f39828014715..e92752f6054a 100644 --- a/dom/plugins/ipc/PluginInstanceParent.cpp +++ b/dom/plugins/ipc/PluginInstanceParent.cpp @@ -7,6 +7,7 @@ #include "mozilla/DebugOnly.h" #include // for intptr_t +#include "mozilla/Preferences.h" #include "mozilla/Telemetry.h" #include "PluginInstanceParent.h" #include "BrowserStreamParent.h" @@ -21,6 +22,7 @@ #include "gfxContext.h" #include "gfxPlatform.h" #include "gfxSharedImageSurface.h" +#include "nsNetUtil.h" #include "nsNPAPIPluginInstance.h" #include "nsPluginInstanceOwner.h" #include "nsFocusManager.h" @@ -54,6 +56,10 @@ extern const wchar_t* kFlashFullscreenClass; #include #endif // defined(XP_MACOSX) +// This is the pref used to determine whether to use Shumway on a Flash object +// (when Shumway is enabled). +static const char kShumwayWhitelistPref[] = "shumway.swf.whitelist"; + using namespace mozilla::plugins; using namespace mozilla::layers; using namespace mozilla::gl; @@ -104,6 +110,7 @@ PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent, , mUseSurrogate(true) , mNPP(npp) , mNPNIface(npniface) + , mIsWhitelistedForShumway(false) , mWindowType(NPWindowTypeWindow) , mDrawingModel(kDefaultDrawingModel) #if defined(OS_WIN) @@ -143,9 +150,38 @@ PluginInstanceParent::~PluginInstanceParent() } bool -PluginInstanceParent::Init() +PluginInstanceParent::InitMetadata(const nsACString& aMimeType, + const nsACString& aSrcAttribute) { - return true; + if (aSrcAttribute.IsEmpty()) { + return false; + } + // Ensure that the src attribute is absolute + nsRefPtr owner = GetOwner(); + if (!owner) { + return false; + } + nsCOMPtr baseUri(owner->GetBaseURI()); + nsresult rv = NS_MakeAbsoluteURI(mSrcAttribute, aSrcAttribute, baseUri); + if (NS_FAILED(rv)) { + return false; + } + // Check the whitelist + nsAutoCString baseUrlSpec; + rv = baseUri->GetSpec(baseUrlSpec); + if (NS_FAILED(rv)) { + return false; + } + auto whitelist = Preferences::GetCString(kShumwayWhitelistPref); + // Empty whitelist is interpreted by CheckWhitelist as "allow everything," + // which is not valid for our use case and should be treated as a failure. + if (whitelist.IsEmpty()) { + return false; + } + rv = nsPluginPlayPreviewInfo::CheckWhitelist(baseUrlSpec, mSrcAttribute, + whitelist, + &mIsWhitelistedForShumway); + return NS_SUCCEEDED(rv); } void diff --git a/dom/plugins/ipc/PluginInstanceParent.h b/dom/plugins/ipc/PluginInstanceParent.h index d5423e2e486b..6d48059d8073 100644 --- a/dom/plugins/ipc/PluginInstanceParent.h +++ b/dom/plugins/ipc/PluginInstanceParent.h @@ -68,7 +68,8 @@ public: virtual ~PluginInstanceParent(); - bool Init(); + bool InitMetadata(const nsACString& aMimeType, + const nsACString& aSrcAttribute); NPError Destroy(); virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE; @@ -271,6 +272,24 @@ public: return mUseSurrogate; } + void + GetSrcAttribute(nsACString& aOutput) const + { + aOutput = mSrcAttribute; + } + + /** + * This function tells us whether this plugin instance would have been + * whitelisted for Shumway if Shumway had been enabled. This is being used + * for the purpose of gathering telemetry on Flash hangs that could + * potentially be avoided by using Shumway instead. + */ + bool + IsWhitelistedForShumway() const + { + return mIsWhitelistedForShumway; + } + virtual bool AnswerPluginFocusChange(const bool& gotFocus) MOZ_OVERRIDE; @@ -323,6 +342,8 @@ private: bool mUseSurrogate; NPP mNPP; const NPNetscapeFuncs* mNPNIface; + nsCString mSrcAttribute; + bool mIsWhitelistedForShumway; NPWindowType mWindowType; int16_t mDrawingModel; nsAutoPtr mNotifySink; diff --git a/dom/plugins/ipc/PluginModuleParent.cpp b/dom/plugins/ipc/PluginModuleParent.cpp index 24e6b8a5e9a7..201d8eaf40d9 100755 --- a/dom/plugins/ipc/PluginModuleParent.cpp +++ b/dom/plugins/ipc/PluginModuleParent.cpp @@ -34,8 +34,10 @@ #include "prsystem.h" #include "GeckoProfiler.h" #include "nsPluginTags.h" +#include "nsUnicharUtils.h" #ifdef XP_WIN +#include "mozilla/plugins/PluginSurfaceParent.h" #include "mozilla/widget/AudioSession.h" #include "PluginHangUIParent.h" #endif @@ -155,6 +157,10 @@ public: void Run() MOZ_OVERRIDE { mParent->DoInjection(mSnapshot); + // We don't need to hold this lock during DoInjection, but we do need + // to obtain it before returning from Run() to ensure that + // PostToMainThread has completed before we return. + mozilla::MutexAutoLock lock(mMutex); } void Cancel() MOZ_OVERRIDE @@ -594,6 +600,7 @@ PluginModuleParent::PluginModuleParent(bool aIsChrome) , mNPPIface(nullptr) , mPlugin(nullptr) , mTaskFactory(this) + , mIsFlashPlugin(false) , mIsStartingAsync(false) , mNPInitialized(false) , mAsyncNewRv(NS_ERROR_NOT_INITIALIZED) @@ -635,13 +642,14 @@ PluginModuleChromeParent::PluginModuleChromeParent(const char* aFilePath, uint32 , mPluginId(aPluginId) , mChromeTaskFactory(this) , mHangAnnotationFlags(0) + , mHangAnnotatorMutex("PluginModuleChromeParent::mHangAnnotatorMutex") #ifdef XP_WIN , mPluginCpuUsageOnHang() , mHangUIParent(nullptr) , mHangUIEnabled(true) , mIsTimerReset(true) #ifdef MOZ_CRASHREPORTER - , mCrashReporterMutex("PluginModuleParent::mCrashReporterMutex") + , mCrashReporterMutex("PluginModuleChromeParent::mCrashReporterMutex") , mCrashReporter(nullptr) #endif #endif @@ -654,7 +662,6 @@ PluginModuleChromeParent::PluginModuleChromeParent(const char* aFilePath, uint32 , mAsyncInitRv(NS_ERROR_NOT_INITIALIZED) , mAsyncInitError(NPERR_NO_ERROR) , mContentParent(nullptr) - , mIsFlashPlugin(false) { NS_ASSERTION(mSubprocess, "Out of memory!"); sInstantiated = true; @@ -902,6 +909,119 @@ GetProcessCpuUsage(const InfallibleTArray& processHandles, #endif // #ifdef XP_WIN +void +PluginModuleChromeParent::OnEnteredCall() +{ + mozilla::ipc::IProtocol* protocol = GetInvokingProtocol(); + MOZ_ASSERT(protocol); + mozilla::MutexAutoLock lock(mHangAnnotatorMutex); + mProtocolCallStack.AppendElement(protocol); +} + +void +PluginModuleChromeParent::OnExitedCall() +{ + mozilla::MutexAutoLock lock(mHangAnnotatorMutex); + MOZ_ASSERT(!mProtocolCallStack.IsEmpty()); + mProtocolCallStack.RemoveElementAt(mProtocolCallStack.Length() - 1); +} + +void +PluginModuleChromeParent::OnEnteredSyncSend() +{ + mozilla::ipc::IProtocol* protocol = GetInvokingProtocol(); + MOZ_ASSERT(protocol); + mozilla::MutexAutoLock lock(mHangAnnotatorMutex); + mProtocolCallStack.AppendElement(protocol); +} + +void +PluginModuleChromeParent::OnExitedSyncSend() +{ + mozilla::MutexAutoLock lock(mHangAnnotatorMutex); + MOZ_ASSERT(!mProtocolCallStack.IsEmpty()); + mProtocolCallStack.RemoveElementAt(mProtocolCallStack.Length() - 1); +} + +/** + * This function converts the topmost routing id on the call stack (as recorded + * by the MessageChannel) into a pointer to a IProtocol object. + */ +mozilla::ipc::IProtocol* +PluginModuleChromeParent::GetInvokingProtocol() +{ + int32_t routingId = GetIPCChannel()->GetTopmostMessageRoutingId(); + // Nothing being routed. No protocol. Just return nullptr. + if (routingId == MSG_ROUTING_NONE) { + return nullptr; + } + // If routingId is MSG_ROUTING_CONTROL then we're dealing with control + // messages that were initiated by the topmost managing protocol, ie. this. + if (routingId == MSG_ROUTING_CONTROL) { + return this; + } + // Otherwise we can look up the protocol object by the routing id. + mozilla::ipc::IProtocol* protocol = Lookup(routingId); + return protocol; +} + +/** + * This function examines the IProtocol object parameter and converts it into + * the PluginInstanceParent object that is associated with that protocol, if + * any. Since PluginInstanceParent manages subprotocols, this function needs + * to determine whether |aProtocol| is a subprotocol, and if so it needs to + * obtain the protocol's manager. + * + * This function needs to be updated if the subprotocols are modified in + * PPluginInstance.ipdl. + */ +PluginInstanceParent* +PluginModuleChromeParent::GetManagingInstance(mozilla::ipc::IProtocol* aProtocol) +{ + MOZ_ASSERT(aProtocol); + mozilla::ipc::MessageListener* listener = + static_cast(aProtocol); + switch (listener->GetProtocolTypeId()) { + case PPluginInstanceMsgStart: + // In this case, aProtocol is the instance itself. Just cast it. + return static_cast(aProtocol); + case PPluginBackgroundDestroyerMsgStart: { + PPluginBackgroundDestroyerParent* actor = + static_cast(aProtocol); + return static_cast(actor->Manager()); + } + case PPluginScriptableObjectMsgStart: { + PPluginScriptableObjectParent* actor = + static_cast(aProtocol); + return static_cast(actor->Manager()); + } + case PBrowserStreamMsgStart: { + PBrowserStreamParent* actor = + static_cast(aProtocol); + return static_cast(actor->Manager()); + } + case PPluginStreamMsgStart: { + PPluginStreamParent* actor = + static_cast(aProtocol); + return static_cast(actor->Manager()); + } + case PStreamNotifyMsgStart: { + PStreamNotifyParent* actor = + static_cast(aProtocol); + return static_cast(actor->Manager()); + } +#ifdef XP_WIN + case PPluginSurfaceMsgStart: { + PPluginSurfaceParent* actor = + static_cast(aProtocol); + return static_cast(actor->Manager()); + } +#endif + default: + return nullptr; + } +} + void PluginModuleChromeParent::EnteredCxxStack() { @@ -944,6 +1064,24 @@ PluginModuleChromeParent::AnnotateHang(mozilla::HangMonitor::HangAnnotations& aA aAnnotations.AddAnnotation(NS_LITERAL_STRING("pluginName"), mPluginName); aAnnotations.AddAnnotation(NS_LITERAL_STRING("pluginVersion"), mPluginVersion); + if (mIsFlashPlugin) { + bool isWhitelistedForShumway = false; + { // Scope for lock + mozilla::MutexAutoLock lock(mHangAnnotatorMutex); + if (!mProtocolCallStack.IsEmpty()) { + mozilla::ipc::IProtocol* topProtocol = + mProtocolCallStack.LastElement(); + PluginInstanceParent* instance = + GetManagingInstance(topProtocol); + if (instance) { + isWhitelistedForShumway = + instance->IsWhitelistedForShumway(); + } + } + } + aAnnotations.AddAnnotation(NS_LITERAL_STRING("pluginIsWhitelistedForShumway"), + isWhitelistedForShumway); + } } } @@ -1107,8 +1245,7 @@ PluginModuleChromeParent::TerminateChildProcess(MessageLoop* aMsgLoop) } bool -PluginModuleParent::GetPluginDetails(nsACString& aPluginName, - nsACString& aPluginVersion) +PluginModuleParent::GetPluginDetails() { nsRefPtr host = nsPluginHost::GetInst(); if (!host) { @@ -1118,8 +1255,9 @@ PluginModuleParent::GetPluginDetails(nsACString& aPluginName, if (!pluginTag) { return false; } - aPluginName = pluginTag->mName; - aPluginVersion = pluginTag->mVersion; + mPluginName = pluginTag->mName; + mPluginVersion = pluginTag->mVersion; + mIsFlashPlugin = pluginTag->mIsFlashPlugin; return true; } @@ -2241,7 +2379,7 @@ PluginModuleParent::NPP_New(NPMIMEType pluginType, NPP instance, } if (mPluginName.IsEmpty()) { - GetPluginDetails(mPluginName, mPluginVersion); + GetPluginDetails(); /** mTimeBlocked measures the time that the main thread has been blocked * on plugin module initialization. As implemented, this is the sum of * plugin-container launch + toolhelp32 snapshot + NP_Initialize. @@ -2271,6 +2409,15 @@ PluginModuleParent::NPP_New(NPMIMEType pluginType, NPP instance, return NS_PLUGIN_INIT_PENDING; } +class nsCaseInsensitiveUTF8StringArrayComparator +{ +public: + template + bool Equals(const A& a, const B& b) const { + return a.Equals(b.get(), nsCaseInsensitiveUTF8StringComparator()); + } +}; + nsresult PluginModuleParent::NPP_NewInternal(NPMIMEType pluginType, NPP instance, uint16_t mode, @@ -2278,13 +2425,20 @@ PluginModuleParent::NPP_NewInternal(NPMIMEType pluginType, NPP instance, InfallibleTArray& values, NPSavedData* saved, NPError* error) { - PluginInstanceParent* parentInstance = - new PluginInstanceParent(this, instance, - nsDependentCString(pluginType), mNPNIface); + nsCaseInsensitiveUTF8StringArrayComparator comparator; + NS_NAMED_LITERAL_CSTRING(srcAttributeName, "src"); + auto srcAttributeIndex = names.IndexOf(srcAttributeName, 0, comparator); + nsAutoCString srcAttribute; + if (srcAttributeIndex != names.NoIndex) { + srcAttribute = values[srcAttributeIndex]; + } - if (!parentInstance->Init()) { - delete parentInstance; - return NS_ERROR_FAILURE; + nsDependentCString strPluginType(pluginType); + PluginInstanceParent* parentInstance = + new PluginInstanceParent(this, instance, strPluginType, mNPNIface); + + if (mIsFlashPlugin) { + parentInstance->InitMetadata(strPluginType, srcAttribute); } // Release the surrogate reference that was in pdata diff --git a/dom/plugins/ipc/PluginModuleParent.h b/dom/plugins/ipc/PluginModuleParent.h index 06a4e5bc7d8e..01d0cbdc5849 100644 --- a/dom/plugins/ipc/PluginModuleParent.h +++ b/dom/plugins/ipc/PluginModuleParent.h @@ -9,7 +9,7 @@ #include "base/process.h" #include "mozilla/FileUtils.h" -#include "mozilla/HangMonitor.h" +#include "mozilla/HangAnnotations.h" #include "mozilla/PluginLibrary.h" #include "mozilla/plugins/PluginProcessParent.h" #include "mozilla/plugins/PPluginModuleParent.h" @@ -287,6 +287,7 @@ protected: TimeDuration mTimeBlocked; nsCString mPluginName; nsCString mPluginVersion; + bool mIsFlashPlugin; #ifdef MOZ_X11 // Dup of plugin's X socket, used to scope its resources to this @@ -295,7 +296,7 @@ protected: #endif bool - GetPluginDetails(nsACString& aPluginName, nsACString& aPluginVersion); + GetPluginDetails(); friend class mozilla::dom::CrashReporterParent; friend class mozilla::plugins::PluginAsyncSurrogate; @@ -389,6 +390,11 @@ class PluginModuleChromeParent void CachedSettingChanged(); + void OnEnteredCall() MOZ_OVERRIDE; + void OnExitedCall() MOZ_OVERRIDE; + void OnEnteredSyncSend() MOZ_OVERRIDE; + void OnExitedSyncSend() MOZ_OVERRIDE; + private: virtual void EnteredCxxStack() MOZ_OVERRIDE; @@ -396,6 +402,9 @@ private: void ExitedCxxStack() MOZ_OVERRIDE; + mozilla::ipc::IProtocol* GetInvokingProtocol(); + PluginInstanceParent* GetManagingInstance(mozilla::ipc::IProtocol* aProtocol); + virtual void AnnotateHang(mozilla::HangMonitor::HangAnnotations& aAnnotations) MOZ_OVERRIDE; @@ -461,6 +470,8 @@ private: kHangUIDontShow = (1u << 3) }; Atomic mHangAnnotationFlags; + mozilla::Mutex mHangAnnotatorMutex; + InfallibleTArray mProtocolCallStack; #ifdef XP_WIN InfallibleTArray mPluginCpuUsageOnHang; PluginHangUIParent *mHangUIParent; @@ -539,7 +550,6 @@ private: NPError mAsyncInitError; dom::ContentParent* mContentParent; nsCOMPtr mOfflineObserver; - bool mIsFlashPlugin; bool mIsBlocklisted; static bool sInstantiated; }; diff --git a/dom/webidl/BluetoothAdapter2.webidl b/dom/webidl/BluetoothAdapter2.webidl index f5e9e3491d9b..96d67fe53896 100644 --- a/dom/webidl/BluetoothAdapter2.webidl +++ b/dom/webidl/BluetoothAdapter2.webidl @@ -53,6 +53,9 @@ interface BluetoothAdapter : EventTarget { // Fired when a remote device gets unpaired from the adapter attribute EventHandler ondeviceunpaired; + // Fired when the pairing process aborted + attribute EventHandler onpairingaborted; + // Fired when a2dp connection status changed attribute EventHandler ona2dpstatuschanged; @@ -78,9 +81,9 @@ interface BluetoothAdapter : EventTarget { Promise disable(); [NewObject, AvailableIn=CertifiedApps] - Promise setName(DOMString aName); + Promise setName(DOMString name); [NewObject] - Promise setDiscoverable(boolean aDiscoverable); + Promise setDiscoverable(boolean discoverable); [NewObject] Promise startDiscovery(); diff --git a/ipc/app/moz.build b/ipc/app/moz.build index 8cc7f0af95a4..842be3ca868e 100644 --- a/ipc/app/moz.build +++ b/ipc/app/moz.build @@ -15,13 +15,16 @@ else: } if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT': kwargs['msvcrt'] = 'static' + if not CONFIG['GNU_CC']: + USE_LIBS += [ + 'mozalloc_staticruntime', + ] GeckoProgram(CONFIG['MOZ_CHILD_PROCESS_NAME'], **kwargs) SOURCES += [ 'MozillaRuntimeMain.cpp', ] USE_LIBS += [ - 'mozalloc', 'nspr', 'xul', ] @@ -51,7 +54,6 @@ if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT': 'sandbox_staticruntime_s', ] DELAYLOAD_DLLS += [ - 'mozalloc.dll', 'nss3.dll', 'xul.dll' ] diff --git a/ipc/glue/GeckoChildProcessHost.cpp b/ipc/glue/GeckoChildProcessHost.cpp index 8cbb2e9a0bfa..cbe58f14b41f 100644 --- a/ipc/glue/GeckoChildProcessHost.cpp +++ b/ipc/glue/GeckoChildProcessHost.cpp @@ -98,7 +98,6 @@ GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType, #if defined(MOZ_SANDBOX) && defined(XP_WIN) mEnableSandboxLogging(false), mSandboxLevel(0), - mMoreStrictSandbox(false), #endif mChildProcessHandle(0) #if defined(MOZ_WIDGET_COCOA) @@ -271,8 +270,7 @@ GeckoChildProcessHost::PrepareLaunch() #if defined(MOZ_CONTENT_SANDBOX) // We need to get the pref here as the process is launched off main thread. if (mProcessType == GeckoProcessType_Content) { - mMoreStrictSandbox = - Preferences::GetBool("security.sandbox.windows.content.moreStrict"); + mSandboxLevel = Preferences::GetInt("security.sandbox.content.level"); mEnableSandboxLogging = Preferences::GetBool("security.sandbox.windows.log"); } @@ -809,7 +807,7 @@ GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector& aExt case GeckoProcessType_Content: #if defined(MOZ_CONTENT_SANDBOX) if (!PR_GetEnv("MOZ_DISABLE_CONTENT_SANDBOX")) { - mSandboxBroker.SetSecurityLevelForContentProcess(mMoreStrictSandbox); + mSandboxBroker.SetSecurityLevelForContentProcess(mSandboxLevel); cmdLine.AppendLooseValue(UTF8ToWide("-sandbox")); shouldSandboxCurrentProcess = true; } diff --git a/ipc/glue/GeckoChildProcessHost.h b/ipc/glue/GeckoChildProcessHost.h index c014c8983459..1ab60af5fc2c 100644 --- a/ipc/glue/GeckoChildProcessHost.h +++ b/ipc/glue/GeckoChildProcessHost.h @@ -174,7 +174,6 @@ protected: std::vector mAllowedFilesReadWrite; bool mEnableSandboxLogging; int32_t mSandboxLevel; - bool mMoreStrictSandbox; #endif #endif // XP_WIN diff --git a/ipc/glue/MessageChannel.cpp b/ipc/glue/MessageChannel.cpp index 43233cab4d61..b337fb33d438 100644 --- a/ipc/glue/MessageChannel.cpp +++ b/ipc/glue/MessageChannel.cpp @@ -193,6 +193,11 @@ public: *name = mMessageName; } + int32_t GetRoutingId() const + { + return mMessageRoutingId; + } + private: const char* mMessageName; int32_t mMessageRoutingId; @@ -1826,6 +1831,17 @@ MessageChannel::DumpInterruptStack(const char* const pfx) const } } +int32_t +MessageChannel::GetTopmostMessageRoutingId() const +{ + MOZ_ASSERT(MessageLoop::current() == mWorkerLoop); + if (mCxxStackFrames.empty()) { + return MSG_ROUTING_NONE; + } + const InterruptFrame& frame = mCxxStackFrames.back(); + return frame.GetRoutingId(); +} + bool ParentProcessIsBlocked() { diff --git a/ipc/glue/MessageChannel.h b/ipc/glue/MessageChannel.h index 4fcd80dc31fe..b22c69202922 100644 --- a/ipc/glue/MessageChannel.h +++ b/ipc/glue/MessageChannel.h @@ -135,6 +135,14 @@ class MessageChannel : HasResultCodes return !mCxxStackFrames.empty(); } + /** + * This function is used by hang annotation code to determine which IPDL + * actor is highest in the call stack at the time of the hang. It should + * be called from the main thread when a sync or intr message is about to + * be sent. + */ + int32_t GetTopmostMessageRoutingId() const; + void FlushPendingInterruptQueue(); // Unsound_IsClosed and Unsound_NumQueuedMessages are safe to call from any diff --git a/js/src/jit-test/tests/asm.js/testAtomics.js b/js/src/jit-test/tests/asm.js/testAtomics.js index 5492a49e1d14..4b222d14cf1c 100644 --- a/js/src/jit-test/tests/asm.js/testAtomics.js +++ b/js/src/jit-test/tests/asm.js/testAtomics.js @@ -177,78 +177,325 @@ function loadModule_int32(stdlib, foreign, heap) { cas2_i: do_cas2_i }; } -// TODO: byte arrays +function loadModule_int8(stdlib, foreign, heap) { + "use asm"; + + var atomic_load = stdlib.Atomics.load; + var atomic_store = stdlib.Atomics.store; + var atomic_cmpxchg = stdlib.Atomics.compareExchange; + var atomic_add = stdlib.Atomics.add; + var atomic_sub = stdlib.Atomics.sub; + var atomic_and = stdlib.Atomics.and; + var atomic_or = stdlib.Atomics.or; + var atomic_xor = stdlib.Atomics.xor; + + var i8a = new stdlib.SharedInt8Array(heap); + + // Load element 0 + function do_load() { + var v = 0; + v = atomic_load(i8a, 0); + return v|0; + } + + // Load element i + function do_load_i(i) { + i = i|0; + var v = 0; + v = atomic_load(i8a, i); + return v|0; + } + + // Store 37 in element 0 + function do_store() { + var v = 0; + v = atomic_store(i8a, 0, 37); + return v|0; + } + + // Store 37 in element i + function do_store_i(i) { + i = i|0; + var v = 0; + v = atomic_store(i8a, i, 37); + return v|0; + } + + // Add 37 to element 10 + function do_add() { + var v = 0; + v = atomic_add(i8a, 10, 37); + return v|0; + } + + // Add 37 to element i + function do_add_i(i) { + i = i|0; + var v = 0; + v = atomic_add(i8a, i, 37); + return v|0; + } + + // Subtract 108 from element 20 + function do_sub() { + var v = 0; + v = atomic_sub(i8a, 20, 108); + return v|0; + } + + // Subtract 108 from element i + function do_sub_i(i) { + i = i|0; + var v = 0; + v = atomic_sub(i8a, i, 108); + return v|0; + } + + // AND 0x33 into element 30 + function do_and() { + var v = 0; + v = atomic_and(i8a, 30, 0x33); + return v|0; + } + + // AND 0x33 into element i + function do_and_i(i) { + i = i|0; + var v = 0; + v = atomic_and(i8a, i, 0x33); + return v|0; + } + + // OR 0x33 into element 40 + function do_or() { + var v = 0; + v = atomic_or(i8a, 40, 0x33); + return v|0; + } + + // OR 0x33 into element i + function do_or_i(i) { + i = i|0; + var v = 0; + v = atomic_or(i8a, i, 0x33); + return v|0; + } + + // XOR 0x33 into element 50 + function do_xor() { + var v = 0; + v = atomic_xor(i8a, 50, 0x33); + return v|0; + } + + // XOR 0x33 into element i + function do_xor_i(i) { + i = i|0; + var v = 0; + v = atomic_xor(i8a, i, 0x33); + return v|0; + } + + // CAS element 100: 0 -> -1 + function do_cas1() { + var v = 0; + v = atomic_cmpxchg(i8a, 100, 0, -1); + return v|0; + } + + // CAS element 100: -1 -> 0x5A + function do_cas2() { + var v = 0; + v = atomic_cmpxchg(i8a, 100, -1, 0x5A); + return v|0; + } + + // CAS element i: 0 -> -1 + function do_cas1_i(i) { + i = i|0; + var v = 0; + v = atomic_cmpxchg(i8a, i, 0, -1); + return v|0; + } + + // CAS element i: -1 -> 0x5A + function do_cas2_i(i) { + i = i|0; + var v = 0; + v = atomic_cmpxchg(i8a, i, -1, 0x5A); + return v|0; + } + + return { load: do_load, + load_i: do_load_i, + store: do_store, + store_i: do_store_i, + add: do_add, + add_i: do_add_i, + sub: do_sub, + sub_i: do_sub_i, + and: do_and, + and_i: do_and_i, + or: do_or, + or_i: do_or_i, + xor: do_xor, + xor_i: do_xor_i, + cas1: do_cas1, + cas2: do_cas2, + cas1_i: do_cas1_i, + cas2_i: do_cas2_i }; +} + // TODO: halfword arrays // TODO: signed vs unsigned; negative results var heap = new SharedArrayBuffer(65536); + +//////////////////////////////////////////////////////////// +// +// int32 tests + var i32a = new SharedInt32Array(heap); -var module = loadModule_int32(this, {}, heap); +var i32m = loadModule_int32(this, {}, heap); var size = 4; -module.fence(); +i32m.fence(); i32a[0] = 12345; -assertEq(module.load(), 12345); -assertEq(module.load_i(size*0), 12345); +assertEq(i32m.load(), 12345); +assertEq(i32m.load_i(size*0), 12345); -assertEq(module.store(), 37); +assertEq(i32m.store(), 37); assertEq(i32a[0], 37); -assertEq(module.store_i(size*0), 37); +assertEq(i32m.store_i(size*0), 37); i32a[10] = 18; -assertEq(module.add(), 18); +assertEq(i32m.add(), 18); assertEq(i32a[10], 18+37); -assertEq(module.add_i(size*10), 18+37); +assertEq(i32m.add_i(size*10), 18+37); assertEq(i32a[10], 18+37+37); i32a[20] = 4972; -assertEq(module.sub(), 4972); +assertEq(i32m.sub(), 4972); assertEq(i32a[20], 4972 - 148); -assertEq(module.sub_i(size*20), 4972 - 148); +assertEq(i32m.sub_i(size*20), 4972 - 148); assertEq(i32a[20], 4972 - 148 - 148); i32a[30] = 0x66666666; -assertEq(module.and(), 0x66666666); +assertEq(i32m.and(), 0x66666666); assertEq(i32a[30], 0x22222222); i32a[30] = 0x66666666; -assertEq(module.and_i(size*30), 0x66666666); +assertEq(i32m.and_i(size*30), 0x66666666); assertEq(i32a[30], 0x22222222); i32a[40] = 0x22222222; -assertEq(module.or(), 0x22222222); +assertEq(i32m.or(), 0x22222222); assertEq(i32a[40], 0x33333333); i32a[40] = 0x22222222; -assertEq(module.or_i(size*40), 0x22222222); +assertEq(i32m.or_i(size*40), 0x22222222); assertEq(i32a[40], 0x33333333); i32a[50] = 0x22222222; -assertEq(module.xor(), 0x22222222); +assertEq(i32m.xor(), 0x22222222); assertEq(i32a[50], 0x11111111); i32a[50] = 0x22222222; -assertEq(module.xor_i(size*50), 0x22222222); +assertEq(i32m.xor_i(size*50), 0x22222222); assertEq(i32a[50], 0x11111111); i32a[100] = 0; -assertEq(module.cas1(), 0); -assertEq(module.cas2(), -1); +assertEq(i32m.cas1(), 0); +assertEq(i32m.cas2(), -1); assertEq(i32a[100], 0x5A5A5A5A); i32a[100] = 0; -assertEq(module.cas1_i(size*100), 0); -assertEq(module.cas2_i(size*100), -1); +assertEq(i32m.cas1_i(size*100), 0); +assertEq(i32m.cas2_i(size*100), -1); assertEq(i32a[100], 0x5A5A5A5A); // Out-of-bounds accesses. -assertEq(module.cas1_i(size*20000), 0); -assertEq(module.cas2_i(size*20000), 0); +assertEq(i32m.cas1_i(size*20000), 0); +assertEq(i32m.cas2_i(size*20000), 0); -assertEq(module.or_i(size*20001), 0); -assertEq(module.xor_i(size*20001), 0); -assertEq(module.and_i(size*20001), 0); -assertEq(module.add_i(size*20001), 0); -assertEq(module.sub_i(size*20001), 0); +assertEq(i32m.or_i(size*20001), 0); +assertEq(i32m.xor_i(size*20001), 0); +assertEq(i32m.and_i(size*20001), 0); +assertEq(i32m.add_i(size*20001), 0); +assertEq(i32m.sub_i(size*20001), 0); + +//////////////////////////////////////////////////////////// +// +// int8 tests + +var i8a = new SharedInt8Array(heap); +var i8m = loadModule_int8(this, {}, heap); + +for ( var i=0 ; i < i8a.length ; i++ ) + i8a[i] = 0; + +var size = 1; + +i8a[0] = 123; +assertEq(i8m.load(), 123); +assertEq(i8m.load_i(0), 123); + +assertEq(i8m.store(), 37); +assertEq(i8a[0], 37); +assertEq(i8m.store_i(0), 37); + +i8a[10] = 18; +assertEq(i8m.add(), 18); +assertEq(i8a[10], 18+37); +assertEq(i8m.add_i(10), 18+37); +assertEq(i8a[10], 18+37+37); + +i8a[20] = 49; +assertEq(i8m.sub(), 49); +assertEq(i8a[20], 49 - 108); +assertEq(i8m.sub_i(20), 49 - 108); +assertEq(i8a[20], ((49 - 108 - 108) << 24) >> 24); // Byte, sign extended + +i8a[30] = 0x66; +assertEq(i8m.and(), 0x66); +assertEq(i8a[30], 0x22); +i8a[30] = 0x66; +assertEq(i8m.and_i(30), 0x66); +assertEq(i8a[30], 0x22); + +i8a[40] = 0x22; +assertEq(i8m.or(), 0x22); +assertEq(i8a[40], 0x33); +i8a[40] = 0x22; +assertEq(i8m.or_i(40), 0x22); +assertEq(i8a[40], 0x33); + +i8a[50] = 0x22; +assertEq(i8m.xor(), 0x22); +assertEq(i8a[50], 0x11); +i8a[50] = 0x22; +assertEq(i8m.xor_i(50), 0x22); +assertEq(i8a[50], 0x11); + +i8a[100] = 0; +assertEq(i8m.cas1(), 0); +assertEq(i8m.cas2(), -1); +assertEq(i8a[100], 0x5A); + +i8a[100] = 0; +assertEq(i8m.cas1_i(100), 0); +assertEq(i8m.cas2_i(100), -1); +assertEq(i8a[100], 0x5A); + +// Out-of-bounds accesses. + +assertEq(i8m.cas1_i(80000), 0); +assertEq(i8m.cas2_i(80000), 0); + +assertEq(i8m.or_i(80001), 0); +assertEq(i8m.xor_i(80001), 0); +assertEq(i8m.and_i(80001), 0); +assertEq(i8m.add_i(80001), 0); +assertEq(i8m.sub_i(80001), 0); print("Done"); diff --git a/js/src/jit-test/tests/profiler/debugmode-osr-resume-addr.js b/js/src/jit-test/tests/profiler/debugmode-osr-resume-addr.js new file mode 100644 index 000000000000..9dd68d628003 --- /dev/null +++ b/js/src/jit-test/tests/profiler/debugmode-osr-resume-addr.js @@ -0,0 +1,11 @@ +enableSPSProfiling(); +try { + // Only the ARM simulator supports single step profiling. + enableSingleStepProfiling(); +} catch (e) { + quit(0); +} +var g = newGlobal(); +var dbg = Debugger(g); +dbg.onDebuggerStatement = function (frame) {}; +g.eval("var line = new Error().lineNumber; debugger;"); diff --git a/js/src/jit-test/tests/structured-clone/Map-Set-cross-compartment.js b/js/src/jit-test/tests/structured-clone/Map-Set-cross-compartment.js index 11ee4e8d2d9f..8ce792562e8d 100644 --- a/js/src/jit-test/tests/structured-clone/Map-Set-cross-compartment.js +++ b/js/src/jit-test/tests/structured-clone/Map-Set-cross-compartment.js @@ -6,3 +6,6 @@ // Don't crash serialize(evalcx("new Set(['x', 'y'])")); serialize(evalcx("new Map([['x', 1]])")); + +assertEq(deserialize(serialize(evalcx("new Set([1, 2, 3])"))).has(1), true); +assertEq(deserialize(serialize(evalcx("new Map([['x', 1]])"))).get('x'), 1); diff --git a/js/src/jit/JitFrameIterator.h b/js/src/jit/JitFrameIterator.h index f70d55ed6337..ebe63f16ccc9 100644 --- a/js/src/jit/JitFrameIterator.h +++ b/js/src/jit/JitFrameIterator.h @@ -280,6 +280,7 @@ class JitProfilingFrameIterator bool tryInitWithPC(void *pc); bool tryInitWithTable(JitcodeGlobalTable *table, void *pc, JSRuntime *rt, bool forLastCallSite); + void fixBaselineDebugModeOSRReturnAddress(); public: JitProfilingFrameIterator(JSRuntime *rt, diff --git a/js/src/jit/JitFrames.cpp b/js/src/jit/JitFrames.cpp index 9140500efcfc..8e0936b8fef1 100644 --- a/js/src/jit/JitFrames.cpp +++ b/js/src/jit/JitFrames.cpp @@ -2898,15 +2898,21 @@ JitProfilingFrameIterator::JitProfilingFrameIterator(void *exitFrame) ExitFrameLayout *frame = (ExitFrameLayout *) exitFrame; FrameType prevType = frame->prevType(); - if (prevType == JitFrame_IonJS || prevType == JitFrame_BaselineJS || - prevType == JitFrame_Unwound_IonJS) - { + if (prevType == JitFrame_IonJS || prevType == JitFrame_Unwound_IonJS) { returnAddressToFp_ = frame->returnAddress(); fp_ = GetPreviousRawFrame(frame); type_ = JitFrame_IonJS; return; } + if (prevType == JitFrame_BaselineJS) { + returnAddressToFp_ = frame->returnAddress(); + fp_ = GetPreviousRawFrame(frame); + type_ = JitFrame_BaselineJS; + fixBaselineDebugModeOSRReturnAddress(); + return; + } + if (prevType == JitFrame_BaselineStub || prevType == JitFrame_Unwound_BaselineStub) { BaselineStubFrameLayout *stubFrame = GetPreviousRawFrame(frame); @@ -2997,6 +3003,16 @@ JitProfilingFrameIterator::tryInitWithTable(JitcodeGlobalTable *table, void *pc, return false; } +void +JitProfilingFrameIterator::fixBaselineDebugModeOSRReturnAddress() +{ + MOZ_ASSERT(type_ == JitFrame_BaselineJS); + BaselineFrame *bl = (BaselineFrame *)(fp_ - BaselineFrame::FramePointerOffset - + BaselineFrame::Size()); + if (BaselineDebugModeOSRInfo *info = bl->getDebugModeOSRInfo()) + returnAddressToFp_ = info->resumeAddr; +} + void JitProfilingFrameIterator::operator++() { @@ -3043,6 +3059,7 @@ JitProfilingFrameIterator::operator++() returnAddressToFp_ = frame->returnAddress(); fp_ = GetPreviousRawFrame(frame); type_ = JitFrame_BaselineJS; + fixBaselineDebugModeOSRReturnAddress(); return; } diff --git a/js/src/jit/shared/Assembler-x86-shared.h b/js/src/jit/shared/Assembler-x86-shared.h index 12fc2490f1de..9f542c460c5c 100644 --- a/js/src/jit/shared/Assembler-x86-shared.h +++ b/js/src/jit/shared/Assembler-x86-shared.h @@ -1105,12 +1105,6 @@ class AssemblerX86Shared : public AssemblerShared MOZ_CRASH("unexpected operand kind"); } } - // Note, lock_addl() is used for a memory barrier on non-SSE2 systems. - // Do not optimize, replace by XADDL, or similar. - void lock_addl(Imm32 imm, const Operand &op) { - masm.prefix_lock(); - addl(imm, op); - } void subl(Imm32 imm, Register dest) { masm.subl_ir(imm.value, dest.code()); } @@ -1129,6 +1123,21 @@ class AssemblerX86Shared : public AssemblerShared void addl(Register src, Register dest) { masm.addl_rr(src.code(), dest.code()); } + void addl(Register src, const Operand &dest) { + switch (dest.kind()) { + case Operand::REG: + masm.addl_rr(src.code(), dest.reg()); + break; + case Operand::MEM_REG_DISP: + masm.addl_rm(src.code(), dest.disp(), dest.base()); + break; + case Operand::MEM_SCALE: + masm.addl_rm(src.code(), dest.disp(), dest.base(), dest.index(), dest.scale()); + break; + default: + MOZ_CRASH("unexpected operand kind"); + } + } void subl(Register src, Register dest) { masm.subl_rr(src.code(), dest.code()); } @@ -1152,6 +1161,9 @@ class AssemblerX86Shared : public AssemblerShared case Operand::MEM_REG_DISP: masm.subl_rm(src.code(), dest.disp(), dest.base()); break; + case Operand::MEM_SCALE: + masm.subl_rm(src.code(), dest.disp(), dest.base(), dest.index(), dest.scale()); + break; default: MOZ_CRASH("unexpected operand kind"); } @@ -1159,6 +1171,21 @@ class AssemblerX86Shared : public AssemblerShared void orl(Register reg, Register dest) { masm.orl_rr(reg.code(), dest.code()); } + void orl(Register src, const Operand &dest) { + switch (dest.kind()) { + case Operand::REG: + masm.orl_rr(src.code(), dest.reg()); + break; + case Operand::MEM_REG_DISP: + masm.orl_rm(src.code(), dest.disp(), dest.base()); + break; + case Operand::MEM_SCALE: + masm.orl_rm(src.code(), dest.disp(), dest.base(), dest.index(), dest.scale()); + break; + default: + MOZ_CRASH("unexpected operand kind"); + } + } void orl(Imm32 imm, Register reg) { masm.orl_ir(imm.value, reg.code()); } @@ -1177,6 +1204,21 @@ class AssemblerX86Shared : public AssemblerShared void xorl(Register src, Register dest) { masm.xorl_rr(src.code(), dest.code()); } + void xorl(Register src, const Operand &dest) { + switch (dest.kind()) { + case Operand::REG: + masm.xorl_rr(src.code(), dest.reg()); + break; + case Operand::MEM_REG_DISP: + masm.xorl_rm(src.code(), dest.disp(), dest.base()); + break; + case Operand::MEM_SCALE: + masm.xorl_rm(src.code(), dest.disp(), dest.base(), dest.index(), dest.scale()); + break; + default: + MOZ_CRASH("unexpected operand kind"); + } + } void xorl(Imm32 imm, Register reg) { masm.xorl_ir(imm.value, reg.code()); } @@ -1195,6 +1237,21 @@ class AssemblerX86Shared : public AssemblerShared void andl(Register src, Register dest) { masm.andl_rr(src.code(), dest.code()); } + void andl(Register src, const Operand &dest) { + switch (dest.kind()) { + case Operand::REG: + masm.andl_rr(src.code(), dest.reg()); + break; + case Operand::MEM_REG_DISP: + masm.andl_rm(src.code(), dest.disp(), dest.base()); + break; + case Operand::MEM_SCALE: + masm.andl_rm(src.code(), dest.disp(), dest.base(), dest.index(), dest.scale()); + break; + default: + MOZ_CRASH("unexpected operand kind"); + } + } void andl(Imm32 imm, Register dest) { masm.andl_ir(imm.value, dest.code()); } @@ -1362,40 +1419,260 @@ class AssemblerX86Shared : public AssemblerShared decl(op); } - void lock_cmpxchg8(Register src, const Operand &mem) { + void addb(Imm32 imm, const Operand &op) { + switch (op.kind()) { + case Operand::MEM_REG_DISP: + masm.addb_im(imm.value, op.disp(), op.base()); + break; + case Operand::MEM_SCALE: + masm.addb_im(imm.value, op.disp(), op.base(), op.index(), op.scale()); + break; + default: + MOZ_CRASH("unexpected operand kind"); + break; + } + } + void addb(Register src, const Operand &op) { + switch (op.kind()) { + case Operand::MEM_REG_DISP: + masm.addb_rm(src.code(), op.disp(), op.base()); + break; + case Operand::MEM_SCALE: + masm.addb_rm(src.code(), op.disp(), op.base(), op.index(), op.scale()); + break; + default: + MOZ_CRASH("unexpected operand kind"); + break; + } + } + + void subb(Imm32 imm, const Operand &op) { + switch (op.kind()) { + case Operand::MEM_REG_DISP: + masm.subb_im(imm.value, op.disp(), op.base()); + break; + case Operand::MEM_SCALE: + masm.subb_im(imm.value, op.disp(), op.base(), op.index(), op.scale()); + break; + default: + MOZ_CRASH("unexpected operand kind"); + break; + } + } + void subb(Register src, const Operand &op) { + switch (op.kind()) { + case Operand::MEM_REG_DISP: + masm.subb_rm(src.code(), op.disp(), op.base()); + break; + case Operand::MEM_SCALE: + masm.subb_rm(src.code(), op.disp(), op.base(), op.index(), op.scale()); + break; + default: + MOZ_CRASH("unexpected operand kind"); + break; + } + } + + void andb(Imm32 imm, const Operand &op) { + switch (op.kind()) { + case Operand::MEM_REG_DISP: + masm.andb_im(imm.value, op.disp(), op.base()); + break; + case Operand::MEM_SCALE: + masm.andb_im(imm.value, op.disp(), op.base(), op.index(), op.scale()); + break; + default: + MOZ_CRASH("unexpected operand kind"); + break; + } + } + void andb(Register src, const Operand &op) { + switch (op.kind()) { + case Operand::MEM_REG_DISP: + masm.andb_rm(src.code(), op.disp(), op.base()); + break; + case Operand::MEM_SCALE: + masm.andb_rm(src.code(), op.disp(), op.base(), op.index(), op.scale()); + break; + default: + MOZ_CRASH("unexpected operand kind"); + break; + } + } + + void orb(Imm32 imm, const Operand &op) { + switch (op.kind()) { + case Operand::MEM_REG_DISP: + masm.orb_im(imm.value, op.disp(), op.base()); + break; + case Operand::MEM_SCALE: + masm.orb_im(imm.value, op.disp(), op.base(), op.index(), op.scale()); + break; + default: + MOZ_CRASH("unexpected operand kind"); + break; + } + } + void orb(Register src, const Operand &op) { + switch (op.kind()) { + case Operand::MEM_REG_DISP: + masm.orb_rm(src.code(), op.disp(), op.base()); + break; + case Operand::MEM_SCALE: + masm.orb_rm(src.code(), op.disp(), op.base(), op.index(), op.scale()); + break; + default: + MOZ_CRASH("unexpected operand kind"); + break; + } + } + + void xorb(Imm32 imm, const Operand &op) { + switch (op.kind()) { + case Operand::MEM_REG_DISP: + masm.xorb_im(imm.value, op.disp(), op.base()); + break; + case Operand::MEM_SCALE: + masm.xorb_im(imm.value, op.disp(), op.base(), op.index(), op.scale()); + break; + default: + MOZ_CRASH("unexpected operand kind"); + break; + } + } + void xorb(Register src, const Operand &op) { + switch (op.kind()) { + case Operand::MEM_REG_DISP: + masm.xorb_rm(src.code(), op.disp(), op.base()); + break; + case Operand::MEM_SCALE: + masm.xorb_rm(src.code(), op.disp(), op.base(), op.index(), op.scale()); + break; + default: + MOZ_CRASH("unexpected operand kind"); + break; + } + } + + template + void lock_addb(T src, const Operand &op) { + masm.prefix_lock(); + addb(src, op); + } + template + void lock_subb(T src, const Operand &op) { + masm.prefix_lock(); + subb(src, op); + } + template + void lock_andb(T src, const Operand &op) { + masm.prefix_lock(); + andb(src, op); + } + template + void lock_orb(T src, const Operand &op) { + masm.prefix_lock(); + orb(src, op); + } + template + void lock_xorb(T src, const Operand &op) { + masm.prefix_lock(); + xorb(src, op); + } + + template + void lock_addw(T src, const Operand &op) { + masm.prefix_lock(); + masm.prefix_16_for_32(); + addl(src, op); + } + template + void lock_subw(T src, const Operand &op) { + masm.prefix_lock(); + masm.prefix_16_for_32(); + subl(src, op); + } + template + void lock_andw(T src, const Operand &op) { + masm.prefix_lock(); + masm.prefix_16_for_32(); + andl(src, op); + } + template + void lock_orw(T src, const Operand &op) { + masm.prefix_lock(); + masm.prefix_16_for_32(); + orl(src, op); + } + template + void lock_xorw(T src, const Operand &op) { + masm.prefix_lock(); + masm.prefix_16_for_32(); + xorl(src, op); + } + + // Note, lock_addl(imm, op) is used for a memory barrier on non-SSE2 systems, + // among other things. Do not optimize, replace by XADDL, or similar. + template + void lock_addl(T src, const Operand &op) { + masm.prefix_lock(); + addl(src, op); + } + template + void lock_subl(T src, const Operand &op) { + masm.prefix_lock(); + subl(src, op); + } + template + void lock_andl(T src, const Operand &op) { + masm.prefix_lock(); + andl(src, op); + } + template + void lock_orl(T src, const Operand &op) { + masm.prefix_lock(); + orl(src, op); + } + template + void lock_xorl(T src, const Operand &op) { + masm.prefix_lock(); + xorl(src, op); + } + + void lock_cmpxchgb(Register src, const Operand &mem) { masm.prefix_lock(); switch (mem.kind()) { case Operand::MEM_REG_DISP: - masm.cmpxchg8(src.code(), mem.disp(), mem.base()); + masm.cmpxchgb(src.code(), mem.disp(), mem.base()); break; case Operand::MEM_SCALE: - masm.cmpxchg8(src.code(), mem.disp(), mem.base(), mem.index(), mem.scale()); + masm.cmpxchgb(src.code(), mem.disp(), mem.base(), mem.index(), mem.scale()); break; default: MOZ_CRASH("unexpected operand kind"); } } - void lock_cmpxchg16(Register src, const Operand &mem) { + void lock_cmpxchgw(Register src, const Operand &mem) { masm.prefix_lock(); switch (mem.kind()) { case Operand::MEM_REG_DISP: - masm.cmpxchg16(src.code(), mem.disp(), mem.base()); + masm.cmpxchgw(src.code(), mem.disp(), mem.base()); break; case Operand::MEM_SCALE: - masm.cmpxchg16(src.code(), mem.disp(), mem.base(), mem.index(), mem.scale()); + masm.cmpxchgw(src.code(), mem.disp(), mem.base(), mem.index(), mem.scale()); break; default: MOZ_CRASH("unexpected operand kind"); } } - void lock_cmpxchg32(Register src, const Operand &mem) { + void lock_cmpxchgl(Register src, const Operand &mem) { masm.prefix_lock(); switch (mem.kind()) { case Operand::MEM_REG_DISP: - masm.cmpxchg32(src.code(), mem.disp(), mem.base()); + masm.cmpxchgl(src.code(), mem.disp(), mem.base()); break; case Operand::MEM_SCALE: - masm.cmpxchg32(src.code(), mem.disp(), mem.base(), mem.index(), mem.scale()); + masm.cmpxchgl(src.code(), mem.disp(), mem.base(), mem.index(), mem.scale()); break; default: MOZ_CRASH("unexpected operand kind"); diff --git a/js/src/jit/shared/BaseAssembler-x86-shared.h b/js/src/jit/shared/BaseAssembler-x86-shared.h index 2490beeff3ce..cba821b388c5 100644 --- a/js/src/jit/shared/BaseAssembler-x86-shared.h +++ b/js/src/jit/shared/BaseAssembler-x86-shared.h @@ -288,6 +288,12 @@ public: m_formatter.oneByteOp(OP_ADD_EvGv, offset, base, src); } + void addl_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale) + { + spew("addl %s, " MEM_obs, GPReg32Name(src), ADDR_obs(offset, base, index, scale)); + m_formatter.oneByteOp(OP_ADD_EvGv, offset, base, index, scale, src); + } + void addl_ir(int32_t imm, RegisterID dst) { spew("addl $%d, %s", imm, GPReg32Name(dst)); @@ -395,18 +401,138 @@ public: } } + void addb_im(int32_t imm, int32_t offset, RegisterID base) { + spew("addb $%d, " MEM_ob, int8_t(imm), ADDR_ob(offset, base)); + m_formatter.oneByteOp(OP_GROUP1_EbIb, offset, base, GROUP1_OP_ADD); + m_formatter.immediate8(imm); + } + + void addb_im(int32_t imm, int32_t offset, RegisterID base, RegisterID index, int scale) + { + spew("addb $%d, " MEM_obs, int8_t(imm), ADDR_obs(offset, base, index, scale)); + m_formatter.oneByteOp(OP_GROUP1_EbIb, offset, base, index, scale, GROUP1_OP_ADD); + m_formatter.immediate8(imm); + } + + void addb_rm(RegisterID src, int32_t offset, RegisterID base) { + spew("addb %s, " MEM_ob, GPReg8Name(src), ADDR_ob(offset, base)); + m_formatter.oneByteOp8(OP_ADD_EbGb, offset, base, src); + } + + void addb_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale) + { + spew("addb %s, " MEM_obs, GPReg8Name(src), ADDR_obs(offset, base, index, scale)); + m_formatter.oneByteOp8(OP_ADD_EbGb, offset, base, index, scale, src); + } + + void subb_im(int32_t imm, int32_t offset, RegisterID base) { + spew("subb $%d, " MEM_ob, int8_t(imm), ADDR_ob(offset, base)); + m_formatter.oneByteOp(OP_GROUP1_EbIb, offset, base, GROUP1_OP_SUB); + m_formatter.immediate8(imm); + } + + void subb_im(int32_t imm, int32_t offset, RegisterID base, RegisterID index, int scale) + { + spew("subb $%d, " MEM_obs, int8_t(imm), ADDR_obs(offset, base, index, scale)); + m_formatter.oneByteOp(OP_GROUP1_EbIb, offset, base, index, scale, GROUP1_OP_SUB); + m_formatter.immediate8(imm); + } + + void subb_rm(RegisterID src, int32_t offset, RegisterID base) { + spew("subb %s, " MEM_ob, GPReg8Name(src), ADDR_ob(offset, base)); + m_formatter.oneByteOp8(OP_SUB_EbGb, offset, base, src); + } + + void subb_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale) + { + spew("subb %s, " MEM_obs, GPReg8Name(src), ADDR_obs(offset, base, index, scale)); + m_formatter.oneByteOp8(OP_SUB_EbGb, offset, base, index, scale, src); + } + + void andb_im(int32_t imm, int32_t offset, RegisterID base) { + spew("andb $%d, " MEM_ob, int8_t(imm), ADDR_ob(offset, base)); + m_formatter.oneByteOp(OP_GROUP1_EbIb, offset, base, GROUP1_OP_AND); + m_formatter.immediate8(imm); + } + + void andb_im(int32_t imm, int32_t offset, RegisterID base, RegisterID index, int scale) + { + spew("andb $%d, " MEM_obs, int8_t(imm), ADDR_obs(offset, base, index, scale)); + m_formatter.oneByteOp(OP_GROUP1_EbIb, offset, base, index, scale, GROUP1_OP_AND); + m_formatter.immediate8(imm); + } + + void andb_rm(RegisterID src, int32_t offset, RegisterID base) { + spew("andb %s, " MEM_ob, GPReg8Name(src), ADDR_ob(offset, base)); + m_formatter.oneByteOp8(OP_AND_EbGb, offset, base, src); + } + + void andb_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale) + { + spew("andb %s, " MEM_obs, GPReg8Name(src), ADDR_obs(offset, base, index, scale)); + m_formatter.oneByteOp8(OP_AND_EbGb, offset, base, index, scale, src); + } + + void orb_im(int32_t imm, int32_t offset, RegisterID base) { + spew("orb $%d, " MEM_ob, int8_t(imm), ADDR_ob(offset, base)); + m_formatter.oneByteOp(OP_GROUP1_EbIb, offset, base, GROUP1_OP_OR); + m_formatter.immediate8(imm); + } + + void orb_im(int32_t imm, int32_t offset, RegisterID base, RegisterID index, int scale) + { + spew("orb $%d, " MEM_obs, int8_t(imm), ADDR_obs(offset, base, index, scale)); + m_formatter.oneByteOp(OP_GROUP1_EbIb, offset, base, index, scale, GROUP1_OP_OR); + m_formatter.immediate8(imm); + } + + void orb_rm(RegisterID src, int32_t offset, RegisterID base) { + spew("orb %s, " MEM_ob, GPReg8Name(src), ADDR_ob(offset, base)); + m_formatter.oneByteOp8(OP_OR_EbGb, offset, base, src); + } + + void orb_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale) + { + spew("orb %s, " MEM_obs, GPReg8Name(src), ADDR_obs(offset, base, index, scale)); + m_formatter.oneByteOp8(OP_OR_EbGb, offset, base, index, scale, src); + } + + void xorb_im(int32_t imm, int32_t offset, RegisterID base) { + spew("xorb $%d, " MEM_ob, int8_t(imm), ADDR_ob(offset, base)); + m_formatter.oneByteOp(OP_GROUP1_EbIb, offset, base, GROUP1_OP_XOR); + m_formatter.immediate8(imm); + } + + void xorb_im(int32_t imm, int32_t offset, RegisterID base, RegisterID index, int scale) + { + spew("xorb $%d, " MEM_obs, int8_t(imm), ADDR_obs(offset, base, index, scale)); + m_formatter.oneByteOp(OP_GROUP1_EbIb, offset, base, index, scale, GROUP1_OP_XOR); + m_formatter.immediate8(imm); + } + + void xorb_rm(RegisterID src, int32_t offset, RegisterID base) { + spew("xorb %s, " MEM_ob, GPReg8Name(src), ADDR_ob(offset, base)); + m_formatter.oneByteOp8(OP_XOR_EbGb, offset, base, src); + } + + void xorb_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale) + { + spew("xorb %s, " MEM_obs, GPReg8Name(src), ADDR_obs(offset, base, index, scale)); + m_formatter.oneByteOp8(OP_XOR_EbGb, offset, base, index, scale, src); + } + void lock_xaddb_rm(RegisterID srcdest, int32_t offset, RegisterID base) { - spew("lock xaddl %s, " MEM_ob, GPReg8Name(srcdest), ADDR_ob(offset, base)); + spew("lock xaddb %s, " MEM_ob, GPReg8Name(srcdest), ADDR_ob(offset, base)); m_formatter.oneByteOp(PRE_LOCK); - m_formatter.twoByteOp(OP2_XADD_EbGb, offset, base, srcdest); + m_formatter.twoByteOp8(OP2_XADD_EbGb, offset, base, srcdest); } void lock_xaddb_rm(RegisterID srcdest, int32_t offset, RegisterID base, RegisterID index, int scale) { - spew("lock xaddl %s, " MEM_obs, GPReg8Name(srcdest), ADDR_obs(offset, base, index, scale)); + spew("lock xaddb %s, " MEM_obs, GPReg8Name(srcdest), ADDR_obs(offset, base, index, scale)); m_formatter.oneByteOp(PRE_LOCK); - m_formatter.twoByteOp(OP2_XADD_EbGb, offset, base, index, scale, srcdest); + m_formatter.twoByteOp8(OP2_XADD_EbGb, offset, base, index, scale, srcdest); } void lock_xaddl_rm(RegisterID srcdest, int32_t offset, RegisterID base) @@ -567,6 +693,12 @@ public: m_formatter.oneByteOp(OP_AND_EvGv, offset, base, src); } + void andl_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale) + { + spew("andl %s, " MEM_obs, GPReg32Name(src), ADDR_obs(offset, base, index, scale)); + m_formatter.oneByteOp(OP_AND_EvGv, offset, base, index, scale, src); + } + void andl_ir(int32_t imm, RegisterID dst) { spew("andl $0x%x, %s", imm, GPReg32Name(dst)); @@ -727,6 +859,12 @@ public: m_formatter.oneByteOp(OP_OR_EvGv, offset, base, src); } + void orl_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale) + { + spew("orl %s, " MEM_obs, GPReg32Name(src), ADDR_obs(offset, base, index, scale)); + m_formatter.oneByteOp(OP_OR_EvGv, offset, base, index, scale, src); + } + void orl_ir(int32_t imm, RegisterID dst) { spew("orl $0x%x, %s", imm, GPReg32Name(dst)); @@ -819,6 +957,12 @@ public: m_formatter.oneByteOp(OP_SUB_EvGv, offset, base, src); } + void subl_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale) + { + spew("subl %s, " MEM_obs, GPReg32Name(src), ADDR_obs(offset, base, index, scale)); + m_formatter.oneByteOp(OP_SUB_EvGv, offset, base, index, scale, src); + } + void subl_ir(int32_t imm, RegisterID dst) { spew("subl $%d, %s", imm, GPReg32Name(dst)); @@ -917,6 +1061,12 @@ public: m_formatter.oneByteOp(OP_XOR_EvGv, offset, base, src); } + void xorl_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale) + { + spew("xorl %s, " MEM_obs, GPReg32Name(src), ADDR_obs(offset, base, index, scale)); + m_formatter.oneByteOp(OP_XOR_EvGv, offset, base, index, scale, src); + } + void xorl_im(int32_t imm, int32_t offset, RegisterID base) { spew("xorl $0x%x, " MEM_ob, imm, ADDR_ob(offset, base)); @@ -1136,41 +1286,41 @@ public: m_formatter.oneByteOp(OP_GROUP5_Ev, offset, base, GROUP5_OP_DEC); } - // Note that CMPXCHG performs comparison against REG = %al/%ax/%eax. + // Note that CMPXCHG performs comparison against REG = %al/%ax/%eax/%rax. // If %REG == [%base+offset], then %src -> [%base+offset]. // Otherwise, [%base+offset] -> %REG. // For the 8-bit operations src must also be an 8-bit register. - void cmpxchg8(RegisterID src, int32_t offset, RegisterID base) + void cmpxchgb(RegisterID src, int32_t offset, RegisterID base) { - spew("cmpxchg8 %s, " MEM_ob, GPRegName(src), ADDR_ob(offset, base)); - m_formatter.twoByteOp(OP2_CMPXCHG_GvEb, offset, base, src); + spew("cmpxchgb %s, " MEM_ob, GPReg8Name(src), ADDR_ob(offset, base)); + m_formatter.twoByteOp8(OP2_CMPXCHG_GvEb, offset, base, src); } - void cmpxchg8(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale) + void cmpxchgb(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale) { - spew("cmpxchg8 %s, " MEM_obs, GPRegName(src), ADDR_obs(offset, base, index, scale)); - m_formatter.twoByteOp(OP2_CMPXCHG_GvEb, offset, base, index, scale, src); + spew("cmpxchgb %s, " MEM_obs, GPReg8Name(src), ADDR_obs(offset, base, index, scale)); + m_formatter.twoByteOp8(OP2_CMPXCHG_GvEb, offset, base, index, scale, src); } - void cmpxchg16(RegisterID src, int32_t offset, RegisterID base) + void cmpxchgw(RegisterID src, int32_t offset, RegisterID base) { - spew("cmpxchg16 %s, " MEM_ob, GPRegName(src), ADDR_ob(offset, base)); + spew("cmpxchgw %s, " MEM_ob, GPReg16Name(src), ADDR_ob(offset, base)); m_formatter.prefix(PRE_OPERAND_SIZE); m_formatter.twoByteOp(OP2_CMPXCHG_GvEw, offset, base, src); } - void cmpxchg16(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale) + void cmpxchgw(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale) { - spew("cmpxchg16 %s, " MEM_obs, GPRegName(src), ADDR_obs(offset, base, index, scale)); + spew("cmpxchgw %s, " MEM_obs, GPReg16Name(src), ADDR_obs(offset, base, index, scale)); m_formatter.prefix(PRE_OPERAND_SIZE); m_formatter.twoByteOp(OP2_CMPXCHG_GvEw, offset, base, index, scale, src); } - void cmpxchg32(RegisterID src, int32_t offset, RegisterID base) + void cmpxchgl(RegisterID src, int32_t offset, RegisterID base) { - spew("cmpxchg32 %s, " MEM_ob, GPRegName(src), ADDR_ob(offset, base)); + spew("cmpxchgl %s, " MEM_ob, GPReg32Name(src), ADDR_ob(offset, base)); m_formatter.twoByteOp(OP2_CMPXCHG_GvEw, offset, base, src); } - void cmpxchg32(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale) + void cmpxchgl(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale) { - spew("cmpxchg32 %s, " MEM_obs, GPRegName(src), ADDR_obs(offset, base, index, scale)); + spew("cmpxchgl %s, " MEM_obs, GPReg32Name(src), ADDR_obs(offset, base, index, scale)); m_formatter.twoByteOp(OP2_CMPXCHG_GvEw, offset, base, index, scale, src); } @@ -1755,7 +1905,7 @@ public: void movb_ir(int32_t imm, RegisterID reg) { spew("movb $0x%x, %s", imm, GPReg8Name(reg)); - m_formatter.oneByteOp(OP_MOV_EbGv, reg); + m_formatter.oneByteOp8(OP_MOV_EbIb, reg); m_formatter.immediate8(imm); } @@ -4700,6 +4850,13 @@ threeByteOpImmSimd("vblendps", VEX_PD, OP3_BLENDPS_VpsWpsIb, ESCAPE_3A, imm, off m_buffer.putByteUnchecked(opcode); } + void oneByteOp8(OneByteOpcodeID opcode, RegisterID r) + { + m_buffer.ensureSpace(MaxInstructionSize); + emitRexIf(byteRegRequiresRex(r), 0, 0, r); + m_buffer.putByteUnchecked(opcode + (r & 7)); + } + void oneByteOp8(OneByteOpcodeID opcode, RegisterID rm, GroupOpcodeID groupOp) { m_buffer.ensureSpace(MaxInstructionSize); @@ -4760,6 +4917,26 @@ threeByteOpImmSimd("vblendps", VEX_PD, OP3_BLENDPS_VpsWpsIb, ESCAPE_3A, imm, off registerModRM(rm, reg); } + void twoByteOp8(TwoByteOpcodeID opcode, int32_t offset, RegisterID base, RegisterID reg) + { + m_buffer.ensureSpace(MaxInstructionSize); + emitRexIf(byteRegRequiresRex(reg)|regRequiresRex(base), reg, 0, base); + m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); + m_buffer.putByteUnchecked(opcode); + memoryModRM(offset, base, reg); + } + + void twoByteOp8(TwoByteOpcodeID opcode, int32_t offset, RegisterID base, RegisterID index, + int scale, RegisterID reg) + { + m_buffer.ensureSpace(MaxInstructionSize); + emitRexIf(byteRegRequiresRex(reg)|regRequiresRex(base)|regRequiresRex(index), + reg, index, base); + m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); + m_buffer.putByteUnchecked(opcode); + memoryModRM(offset, base, index, scale, reg); + } + // Like twoByteOp8 but doesn't add a REX prefix if the destination reg // is in esp..edi. This may be used when the destination is not an 8-bit // register (as in a movzbl instruction), so it doesn't need a REX @@ -4947,7 +5124,8 @@ threeByteOpImmSimd("vblendps", VEX_PD, OP3_BLENDPS_VpsWpsIb, ESCAPE_3A, imm, off // // NB: WebKit's use of emitRexIf() is limited such that the // reqRequiresRex() checks are not needed. SpiderMonkey extends - // oneByteOp8 functionality such that r, x, and b can all be used. + // oneByteOp8 and twoByteOp8 functionality such that r, x, and b + // can all be used. void emitRexIf(bool condition, int r, int x, int b) { if (condition || diff --git a/js/src/jit/shared/Encoding-x86-shared.h b/js/src/jit/shared/Encoding-x86-shared.h index 1c2360b0a21f..a96ad4022dad 100644 --- a/js/src/jit/shared/Encoding-x86-shared.h +++ b/js/src/jit/shared/Encoding-x86-shared.h @@ -89,6 +89,7 @@ enum OneByteOpcodeID { OP_MOV_OvEAX = 0xA3, OP_TEST_EAXIb = 0xA8, OP_TEST_EAXIv = 0xA9, + OP_MOV_EbIb = 0xB0, OP_MOV_EAXIv = 0xB8, OP_GROUP2_EvIb = 0xC1, OP_RET_Iz = 0xC2, diff --git a/js/src/jit/shared/Lowering-x86-shared.cpp b/js/src/jit/shared/Lowering-x86-shared.cpp index 6163ee908f8c..f86125c09349 100644 --- a/js/src/jit/shared/Lowering-x86-shared.cpp +++ b/js/src/jit/shared/Lowering-x86-shared.cpp @@ -364,7 +364,8 @@ LIRGeneratorX86Shared::lowerTruncateFToInt32(MTruncateToInt32 *ins) } void -LIRGeneratorX86Shared::visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement *ins) +LIRGeneratorX86Shared::lowerCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement *ins, + bool useI386ByteRegisters) { MOZ_ASSERT(ins->arrayType() != Scalar::Float32); MOZ_ASSERT(ins->arrayType() != Scalar::Float64); @@ -385,12 +386,11 @@ LIRGeneratorX86Shared::visitCompareExchangeTypedArrayElement(MCompareExchangeTyp // // oldval must be in a register. // - // newval will need to be in a register. If the source is a byte - // array then the newval must be a register that has a byte size: - // ebx, ecx, or edx, since eax is taken for the output in this - // case. + // newval must be in a register. If the source is a byte array + // then newval must be a register that has a byte size: on x86 + // this must be ebx, ecx, or edx (eax is taken for the output). // - // Bug #1077036 describes some optimization opportunities. + // Bug #1077036 describes some further optimization opportunities. bool fixedOutput = false; LDefinition tempDef = LDefinition::BogusTemp(); @@ -400,13 +400,12 @@ LIRGeneratorX86Shared::visitCompareExchangeTypedArrayElement(MCompareExchangeTyp newval = useRegister(ins->newval()); } else { fixedOutput = true; - if (ins->isByteArray()) + if (useI386ByteRegisters && ins->isByteArray()) newval = useFixed(ins->newval(), ebx); else newval = useRegister(ins->newval()); } - // A register allocator limitation precludes 'useRegisterAtStart()' here. const LAllocation oldval = useRegister(ins->oldval()); LCompareExchangeTypedArrayElement *lir = @@ -419,7 +418,8 @@ LIRGeneratorX86Shared::visitCompareExchangeTypedArrayElement(MCompareExchangeTyp } void -LIRGeneratorX86Shared::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop *ins) +LIRGeneratorX86Shared::lowerAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop *ins, + bool useI386ByteRegisters) { MOZ_ASSERT(ins->arrayType() != Scalar::Uint8Clamped); MOZ_ASSERT(ins->arrayType() != Scalar::Float32); @@ -452,7 +452,7 @@ LIRGeneratorX86Shared::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElemen // // Note the placement of L, cmpxchg will update eax with *mem if // *mem does not have the expected value, so reloading it at the - // top of the loop is redundant. + // top of the loop would be redundant. // // If the array is not a uint32 array then: // - eax should be the output (one result of the cmpxchg) @@ -488,12 +488,11 @@ LIRGeneratorX86Shared::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElemen } else { tempDef1 = temp(); } - } else if (ins->isByteArray()) { + } else if (useI386ByteRegisters && ins->isByteArray()) { value = useFixed(ins->value(), ebx); if (bitOp) tempDef1 = tempFixed(ecx); - } - else { + } else { value = useRegister(ins->value()); if (bitOp) tempDef1 = temp(); @@ -508,133 +507,6 @@ LIRGeneratorX86Shared::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElemen define(lir, ins); } -void -LIRGeneratorX86Shared::lowerAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap *ins, - const LDefinition& addrTemp) -{ - MDefinition *ptr = ins->ptr(); - MOZ_ASSERT(ptr->type() == MIRType_Int32); - - bool byteArray = false; - switch (ins->accessType()) { - case Scalar::Int8: - case Scalar::Uint8: - byteArray = true; - break; - case Scalar::Int16: - case Scalar::Uint16: - case Scalar::Int32: - case Scalar::Uint32: - break; - default: - MOZ_CRASH("Unexpected array type"); - } - - // Register allocation: - // - // The output must be eax. - // - // oldval must be in a register (it'll eventually end up in eax so - // ideally it's there to begin with). - // - // newval will need to be in a register. If the source is a byte - // array then the newval must be a register that has a byte size: - // ebx, ecx, or edx, since eax is taken for the output in this - // case. We pick ebx but it would be more flexible to pick any of - // the three that wasn't being used. - // - // Bug #1077036 describes some optimization opportunities. - - const LAllocation newval = byteArray ? useFixed(ins->newValue(), ebx) : useRegister(ins->newValue()); - const LAllocation oldval = useRegister(ins->oldValue()); - - LAsmJSCompareExchangeHeap *lir = - new(alloc()) LAsmJSCompareExchangeHeap(useRegister(ptr), oldval, newval); - - lir->setAddrTemp(addrTemp); - defineFixed(lir, ins, LAllocation(AnyRegister(eax))); -} - -void -LIRGeneratorX86Shared::lowerAsmJSAtomicBinopHeap(MAsmJSAtomicBinopHeap *ins, - const LDefinition& addrTemp) -{ - MDefinition *ptr = ins->ptr(); - MOZ_ASSERT(ptr->type() == MIRType_Int32); - - bool byteArray = false; - switch (ins->accessType()) { - case Scalar::Int8: - case Scalar::Uint8: - byteArray = true; - break; - case Scalar::Int16: - case Scalar::Uint16: - case Scalar::Int32: - case Scalar::Uint32: - break; - default: - MOZ_CRASH("Unexpected array type"); - } - - // Register allocation: - // - // For ADD and SUB we'll use XADD: - // - // movl value, output - // lock xaddl output, mem - // - // For the 8-bit variants XADD needs a byte register for the - // output only, we can still set up with movl; just pin the output - // to eax (or ebx / ecx / edx). - // - // For AND/OR/XOR we need to use a CMPXCHG loop: - // - // movl *mem, eax - // L: mov eax, temp - // andl value, temp - // lock cmpxchg temp, mem ; reads eax also - // jnz L - // ; result in eax - // - // Note the placement of L, cmpxchg will update eax with *mem if - // *mem does not have the expected value, so reloading it at the - // top of the loop is redundant. - // - // We want to fix eax as the output. We also need a temp for - // the intermediate value. - // - // For the 8-bit variants the temp must have a byte register. - // - // There are optimization opportunities: - // - when the result is unused, Bug #1077014. - // - better register allocation and instruction selection, Bug #1077036. - - bool bitOp = !(ins->operation() == AtomicFetchAddOp || ins->operation() == AtomicFetchSubOp); - LDefinition tempDef = LDefinition::BogusTemp(); - LAllocation value; - - // Optimization opportunity: "value" need not be pinned to something that - // has a byte register unless the back-end insists on using a byte move - // for the setup or the payload computation, which really it need not do. - - if (byteArray) { - value = useFixed(ins->value(), ebx); - if (bitOp) - tempDef = tempFixed(ecx); - } else { - value = useRegister(ins->value()); - if (bitOp) - tempDef = temp(); - } - - LAsmJSAtomicBinopHeap *lir = - new(alloc()) LAsmJSAtomicBinopHeap(useRegister(ptr), value, tempDef); - - lir->setAddrTemp(addrTemp); - defineFixed(lir, ins, LAllocation(AnyRegister(eax))); -} - void LIRGeneratorX86Shared::visitSimdBinaryArith(MSimdBinaryArith *ins) { diff --git a/js/src/jit/shared/Lowering-x86-shared.h b/js/src/jit/shared/Lowering-x86-shared.h index ab9e491843e3..7bd1e3031e5b 100644 --- a/js/src/jit/shared/Lowering-x86-shared.h +++ b/js/src/jit/shared/Lowering-x86-shared.h @@ -56,10 +56,10 @@ class LIRGeneratorX86Shared : public LIRGeneratorShared void visitSimdSelect(MSimdSelect *ins); void visitSimdSplatX4(MSimdSplatX4 *ins); void visitSimdValueX4(MSimdValueX4 *ins); - void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement *ins); - void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop *ins); - void lowerAsmJSAtomicBinopHeap(MAsmJSAtomicBinopHeap *ins, const LDefinition& addrTemp); - void lowerAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap *ins, const LDefinition& addrTemp); + void lowerCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement *ins, + bool useI386ByteRegisters); + void lowerAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop *ins, + bool useI386ByteRegisters); }; } // namespace jit diff --git a/js/src/jit/shared/MacroAssembler-x86-shared.h b/js/src/jit/shared/MacroAssembler-x86-shared.h index 9168268e7713..42cdcb30b7aa 100644 --- a/js/src/jit/shared/MacroAssembler-x86-shared.h +++ b/js/src/jit/shared/MacroAssembler-x86-shared.h @@ -16,6 +16,19 @@ # include "jit/x64/Assembler-x64.h" #endif +#ifdef DEBUG + #define CHECK_BYTEREG(reg) \ + GeneralRegisterSet byteRegs(Registers::SingleByteRegs); \ + MOZ_ASSERT(byteRegs.has(reg)) + #define CHECK_BYTEREGS(r1, r2) \ + GeneralRegisterSet byteRegs(Registers::SingleByteRegs); \ + MOZ_ASSERT(byteRegs.has(r1)); \ + MOZ_ASSERT(byteRegs.has(r2)); +#else + #define CHECK_BYTEREG(reg) (void)0 + #define CHECK_BYTEREGS(r1, r2) (void)0 +#endif + namespace js { namespace jit { @@ -211,25 +224,10 @@ class MacroAssemblerX86Shared : public Assembler void atomic_dec32(const Operand &addr) { lock_decl(addr); } - void atomic_cmpxchg8(Register newval, const Operand &addr, Register oldval_and_result) { - // %eax must be explicitly provided for calling clarity. - MOZ_ASSERT(oldval_and_result.code() == X86Encoding::rax); - lock_cmpxchg8(newval, addr); - } - void atomic_cmpxchg16(Register newval, const Operand &addr, Register oldval_and_result) { - // %eax must be explicitly provided for calling clarity. - MOZ_ASSERT(oldval_and_result.code() == X86Encoding::rax); - lock_cmpxchg16(newval, addr); - } - void atomic_cmpxchg32(Register newval, const Operand &addr, Register oldval_and_result) { - // %eax must be explicitly provided for calling clarity. - MOZ_ASSERT(oldval_and_result.code() == X86Encoding::rax); - lock_cmpxchg32(newval, addr); - } template void atomicFetchAdd8SignExtend(Register src, const T &mem, Register temp, Register output) { - MOZ_ASSERT(output == eax); + CHECK_BYTEREGS(src, output); if (src != output) movl(src, output); lock_xaddb(output, Operand(mem)); @@ -238,7 +236,7 @@ class MacroAssemblerX86Shared : public Assembler template void atomicFetchAdd8ZeroExtend(Register src, const T &mem, Register temp, Register output) { - MOZ_ASSERT(output == eax); + CHECK_BYTEREGS(src, output); MOZ_ASSERT(temp == InvalidReg); if (src != output) movl(src, output); @@ -248,7 +246,7 @@ class MacroAssemblerX86Shared : public Assembler template void atomicFetchAdd8SignExtend(Imm32 src, const T &mem, Register temp, Register output) { - MOZ_ASSERT(output == eax); + CHECK_BYTEREG(output); MOZ_ASSERT(temp == InvalidReg); movb(src, output); lock_xaddb(output, Operand(mem)); @@ -257,7 +255,7 @@ class MacroAssemblerX86Shared : public Assembler template void atomicFetchAdd8ZeroExtend(Imm32 src, const T &mem, Register temp, Register output) { - MOZ_ASSERT(output == eax); + CHECK_BYTEREG(output); MOZ_ASSERT(temp == InvalidReg); movb(src, output); lock_xaddb(output, Operand(mem)); @@ -315,7 +313,7 @@ class MacroAssemblerX86Shared : public Assembler template void atomicFetchSub8SignExtend(Register src, const T &mem, Register temp, Register output) { - MOZ_ASSERT(output == eax); + CHECK_BYTEREGS(src, output); MOZ_ASSERT(temp == InvalidReg); if (src != output) movl(src, output); @@ -326,7 +324,7 @@ class MacroAssemblerX86Shared : public Assembler template void atomicFetchSub8ZeroExtend(Register src, const T &mem, Register temp, Register output) { - MOZ_ASSERT(output == eax); + CHECK_BYTEREGS(src, output); MOZ_ASSERT(temp == InvalidReg); if (src != output) movl(src, output); @@ -337,7 +335,7 @@ class MacroAssemblerX86Shared : public Assembler template void atomicFetchSub8SignExtend(Imm32 src, const T &mem, Register temp, Register output) { - MOZ_ASSERT(output == eax); + CHECK_BYTEREG(output); MOZ_ASSERT(temp == InvalidReg); movb(Imm32(-src.value), output); lock_xaddb(output, Operand(mem)); @@ -346,7 +344,7 @@ class MacroAssemblerX86Shared : public Assembler template void atomicFetchSub8ZeroExtend(Imm32 src, const T &mem, Register temp, Register output) { - MOZ_ASSERT(output == eax); + CHECK_BYTEREG(output); MOZ_ASSERT(temp == InvalidReg); movb(Imm32(-src.value), output); lock_xaddb(output, Operand(mem)); @@ -405,89 +403,95 @@ class MacroAssemblerX86Shared : public Assembler } // requires output == eax -#define ATOMIC_BITOP_BODY(LOAD, OP, LOCK_CMPXCHG) \ - MOZ_ASSERT(output == eax); \ - LOAD(Operand(mem), eax); \ - Label again; \ - bind(&again); \ - movl(eax, temp); \ - OP(src, temp); \ - LOCK_CMPXCHG(temp, Operand(mem)); \ +#define ATOMIC_BITOP_BODY(LOAD, OP, LOCK_CMPXCHG) \ + MOZ_ASSERT(output == eax); \ + LOAD(Operand(mem), eax); \ + Label again; \ + bind(&again); \ + movl(eax, temp); \ + OP(src, temp); \ + LOCK_CMPXCHG(temp, Operand(mem)); \ j(NonZero, &again); template void atomicFetchAnd8SignExtend(const S &src, const T &mem, Register temp, Register output) { - ATOMIC_BITOP_BODY(movb, andl, lock_cmpxchg8) + ATOMIC_BITOP_BODY(movb, andl, lock_cmpxchgb) + CHECK_BYTEREG(temp); movsbl(eax, eax); } template void atomicFetchAnd8ZeroExtend(const S &src, const T &mem, Register temp, Register output) { - ATOMIC_BITOP_BODY(movb, andl, lock_cmpxchg8) + ATOMIC_BITOP_BODY(movb, andl, lock_cmpxchgb) + CHECK_BYTEREG(temp); movzbl(eax, eax); } template void atomicFetchAnd16SignExtend(const S &src, const T &mem, Register temp, Register output) { - ATOMIC_BITOP_BODY(movw, andl, lock_cmpxchg16) + ATOMIC_BITOP_BODY(movw, andl, lock_cmpxchgw) movswl(eax, eax); } template void atomicFetchAnd16ZeroExtend(const S &src, const T &mem, Register temp, Register output) { - ATOMIC_BITOP_BODY(movw, andl, lock_cmpxchg16) + ATOMIC_BITOP_BODY(movw, andl, lock_cmpxchgw) movzwl(eax, eax); } template void atomicFetchAnd32(const S &src, const T &mem, Register temp, Register output) { - ATOMIC_BITOP_BODY(movl, andl, lock_cmpxchg32) + ATOMIC_BITOP_BODY(movl, andl, lock_cmpxchgl) } template void atomicFetchOr8SignExtend(const S &src, const T &mem, Register temp, Register output) { - ATOMIC_BITOP_BODY(movb, orl, lock_cmpxchg8) + ATOMIC_BITOP_BODY(movb, orl, lock_cmpxchgb) + CHECK_BYTEREG(temp); movsbl(eax, eax); } template void atomicFetchOr8ZeroExtend(const S &src, const T &mem, Register temp, Register output) { - ATOMIC_BITOP_BODY(movb, orl, lock_cmpxchg8) + ATOMIC_BITOP_BODY(movb, orl, lock_cmpxchgb) + CHECK_BYTEREG(temp); movzbl(eax, eax); } template void atomicFetchOr16SignExtend(const S &src, const T &mem, Register temp, Register output) { - ATOMIC_BITOP_BODY(movw, orl, lock_cmpxchg16) + ATOMIC_BITOP_BODY(movw, orl, lock_cmpxchgw) movswl(eax, eax); } template void atomicFetchOr16ZeroExtend(const S &src, const T &mem, Register temp, Register output) { - ATOMIC_BITOP_BODY(movw, orl, lock_cmpxchg16) + ATOMIC_BITOP_BODY(movw, orl, lock_cmpxchgw) movzwl(eax, eax); } template void atomicFetchOr32(const S &src, const T &mem, Register temp, Register output) { - ATOMIC_BITOP_BODY(movl, orl, lock_cmpxchg32) + ATOMIC_BITOP_BODY(movl, orl, lock_cmpxchgl) } template void atomicFetchXor8SignExtend(const S &src, const T &mem, Register temp, Register output) { - ATOMIC_BITOP_BODY(movb, xorl, lock_cmpxchg8) + ATOMIC_BITOP_BODY(movb, xorl, lock_cmpxchgb) + CHECK_BYTEREG(temp); movsbl(eax, eax); } template void atomicFetchXor8ZeroExtend(const S &src, const T &mem, Register temp, Register output) { - ATOMIC_BITOP_BODY(movb, xorl, lock_cmpxchg8) + ATOMIC_BITOP_BODY(movb, xorl, lock_cmpxchgb) + CHECK_BYTEREG(temp); movzbl(eax, eax); } template void atomicFetchXor16SignExtend(const S &src, const T &mem, Register temp, Register output) { - ATOMIC_BITOP_BODY(movw, xorl, lock_cmpxchg16) + ATOMIC_BITOP_BODY(movw, xorl, lock_cmpxchgw) movswl(eax, eax); } template void atomicFetchXor16ZeroExtend(const S &src, const T &mem, Register temp, Register output) { - ATOMIC_BITOP_BODY(movw, xorl, lock_cmpxchg16) + ATOMIC_BITOP_BODY(movw, xorl, lock_cmpxchgw) movzwl(eax, eax); } template void atomicFetchXor32(const S &src, const T &mem, Register temp, Register output) { - ATOMIC_BITOP_BODY(movl, xorl, lock_cmpxchg32) + ATOMIC_BITOP_BODY(movl, xorl, lock_cmpxchgl) } #undef ATOMIC_BITOP_BODY @@ -716,19 +720,19 @@ class MacroAssemblerX86Shared : public Assembler template void compareExchange8ZeroExtend(const T &mem, Register oldval, Register newval, Register output) { MOZ_ASSERT(output == eax); - MOZ_ASSERT(newval == ebx || newval == ecx || newval == edx); + CHECK_BYTEREGS(oldval, newval); if (oldval != output) movl(oldval, output); - lock_cmpxchg8(newval, Operand(mem)); + lock_cmpxchgb(newval, Operand(mem)); movzbl(output, output); } template void compareExchange8SignExtend(const T &mem, Register oldval, Register newval, Register output) { MOZ_ASSERT(output == eax); - MOZ_ASSERT(newval == ebx || newval == ecx || newval == edx); + CHECK_BYTEREGS(oldval, newval); if (oldval != output) movl(oldval, output); - lock_cmpxchg8(newval, Operand(mem)); + lock_cmpxchgb(newval, Operand(mem)); movsbl(output, output); } void load16ZeroExtend(const Address &src, Register dest) { @@ -746,7 +750,7 @@ class MacroAssemblerX86Shared : public Assembler MOZ_ASSERT(output == eax); if (oldval != output) movl(oldval, output); - lock_cmpxchg16(newval, Operand(mem)); + lock_cmpxchgw(newval, Operand(mem)); movzwl(output, output); } template @@ -754,7 +758,7 @@ class MacroAssemblerX86Shared : public Assembler MOZ_ASSERT(output == eax); if (oldval != output) movl(oldval, output); - lock_cmpxchg16(newval, Operand(mem)); + lock_cmpxchgw(newval, Operand(mem)); movswl(output, output); } void load16SignExtend(const Address &src, Register dest) { @@ -781,7 +785,7 @@ class MacroAssemblerX86Shared : public Assembler MOZ_ASSERT(output == eax); if (oldval != output) movl(oldval, output); - lock_cmpxchg32(newval, Operand(mem)); + lock_cmpxchgl(newval, Operand(mem)); } template void store32_NoSecondScratch(const S &src, const T &dest) { @@ -1344,4 +1348,7 @@ class MacroAssemblerX86Shared : public Assembler } // namespace jit } // namespace js +#undef CHECK_BYTEREG +#undef CHECK_BYTEREGS + #endif /* jit_shared_MacroAssembler_x86_shared_h */ diff --git a/js/src/jit/x64/Lowering-x64.cpp b/js/src/jit/x64/Lowering-x64.cpp index 7b5c5be1c168..ec5c5c511520 100644 --- a/js/src/jit/x64/Lowering-x64.cpp +++ b/js/src/jit/x64/Lowering-x64.cpp @@ -131,6 +131,18 @@ LIRGeneratorX64::lowerUntypedPhiInput(MPhi *phi, uint32_t inputPosition, LBlock lowerTypedPhiInput(phi, inputPosition, block, lirIndex); } +void +LIRGeneratorX64::visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement *ins) +{ + lowerCompareExchangeTypedArrayElement(ins, /* useI386ByteRegisters = */ false); +} + +void +LIRGeneratorX64::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop *ins) +{ + lowerAtomicTypedArrayElementBinop(ins, /* useI386ByteRegisters = */ false); +} + void LIRGeneratorX64::visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins) { @@ -200,13 +212,58 @@ LIRGeneratorX64::visitAsmJSStoreHeap(MAsmJSStoreHeap *ins) void LIRGeneratorX64::visitAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap *ins) { - lowerAsmJSCompareExchangeHeap(ins, LDefinition::BogusTemp()); + MDefinition *ptr = ins->ptr(); + MOZ_ASSERT(ptr->type() == MIRType_Int32); + + const LAllocation oldval = useRegister(ins->oldValue()); + const LAllocation newval = useRegister(ins->newValue()); + + LAsmJSCompareExchangeHeap *lir = + new(alloc()) LAsmJSCompareExchangeHeap(useRegister(ptr), oldval, newval); + + defineFixed(lir, ins, LAllocation(AnyRegister(eax))); } void LIRGeneratorX64::visitAsmJSAtomicBinopHeap(MAsmJSAtomicBinopHeap *ins) { - lowerAsmJSAtomicBinopHeap(ins, LDefinition::BogusTemp()); + MDefinition *ptr = ins->ptr(); + MOZ_ASSERT(ptr->type() == MIRType_Int32); + + // Register allocation: + // + // For ADD and SUB we'll use XADD (with word and byte ops as appropriate): + // + // movl value, output + // lock xaddl output, mem + // + // For AND/OR/XOR we need to use a CMPXCHG loop: + // + // movl *mem, eax + // L: mov eax, temp + // andl value, temp + // lock cmpxchg temp, mem ; reads eax also + // jnz L + // ; result in eax + // + // Note the placement of L, cmpxchg will update eax with *mem if + // *mem does not have the expected value, so reloading it at the + // top of the loop would be redundant. + // + // We want to fix eax as the output. We also need a temp for + // the intermediate value. + // + // There are optimization opportunities: + // - when the result is unused, Bug #1077014. + + bool bitOp = !(ins->operation() == AtomicFetchAddOp || ins->operation() == AtomicFetchSubOp); + LAllocation value = useRegister(ins->value()); + LDefinition tempDef = bitOp ? temp() : LDefinition::BogusTemp(); + + LAsmJSAtomicBinopHeap *lir = + new(alloc()) LAsmJSAtomicBinopHeap(useRegister(ptr), value, tempDef); + + defineFixed(lir, ins, LAllocation(AnyRegister(eax))); } void diff --git a/js/src/jit/x64/Lowering-x64.h b/js/src/jit/x64/Lowering-x64.h index 708695e9710a..aa1b87688d06 100644 --- a/js/src/jit/x64/Lowering-x64.h +++ b/js/src/jit/x64/Lowering-x64.h @@ -42,6 +42,8 @@ class LIRGeneratorX64 : public LIRGeneratorX86Shared void visitBox(MBox *box); void visitUnbox(MUnbox *unbox); void visitReturn(MReturn *ret); + void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement *ins); + void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop *ins); void visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins); void visitAsmJSUnsignedToFloat32(MAsmJSUnsignedToFloat32 *ins); void visitAsmJSLoadHeap(MAsmJSLoadHeap *ins); diff --git a/js/src/jit/x86/Lowering-x86.cpp b/js/src/jit/x86/Lowering-x86.cpp index 206df7fdd30e..8292dffb1ab8 100644 --- a/js/src/jit/x86/Lowering-x86.cpp +++ b/js/src/jit/x86/Lowering-x86.cpp @@ -182,6 +182,18 @@ LIRGeneratorX86::lowerUntypedPhiInput(MPhi *phi, uint32_t inputPosition, LBlock payload->setOperand(inputPosition, LUse(VirtualRegisterOfPayload(operand), LUse::ANY)); } +void +LIRGeneratorX86::visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement *ins) +{ + lowerCompareExchangeTypedArrayElement(ins, /* useI386ByteRegisters = */ true); +} + +void +LIRGeneratorX86::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop *ins) +{ + lowerAtomicTypedArrayElementBinop(ins, /* useI386ByteRegisters = */ true); +} + void LIRGeneratorX86::visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins) { @@ -273,13 +285,101 @@ LIRGeneratorX86::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic void LIRGeneratorX86::visitAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap *ins) { - lowerAsmJSCompareExchangeHeap(ins, temp()); + MOZ_ASSERT(ins->accessType() < Scalar::Float32); + + MDefinition *ptr = ins->ptr(); + MOZ_ASSERT(ptr->type() == MIRType_Int32); + + bool byteArray = byteSize(ins->accessType()) == 1; + + // Register allocation: + // + // The output must be eax. + // + // oldval must be in a register. + // + // newval must be in a register. If the source is a byte array + // then newval must be a register that has a byte size: on x86 + // this must be ebx, ecx, or edx (eax is taken for the output). + // + // Bug #1077036 describes some optimization opportunities. + + const LAllocation oldval = useRegister(ins->oldValue()); + const LAllocation newval = byteArray ? useFixed(ins->newValue(), ebx) : useRegister(ins->newValue()); + + LAsmJSCompareExchangeHeap *lir = + new(alloc()) LAsmJSCompareExchangeHeap(useRegister(ptr), oldval, newval); + + lir->setAddrTemp(temp()); + defineFixed(lir, ins, LAllocation(AnyRegister(eax))); } void LIRGeneratorX86::visitAsmJSAtomicBinopHeap(MAsmJSAtomicBinopHeap *ins) { - lowerAsmJSAtomicBinopHeap(ins, temp()); + MOZ_ASSERT(ins->accessType() < Scalar::Float32); + + MDefinition *ptr = ins->ptr(); + MOZ_ASSERT(ptr->type() == MIRType_Int32); + + bool byteArray = byteSize(ins->accessType()) == 1; + + // Register allocation: + // + // For ADD and SUB we'll use XADD: + // + // movl value, output + // lock xaddl output, mem + // + // For the 8-bit variants XADD needs a byte register for the + // output only, we can still set up with movl; just pin the output + // to eax (or ebx / ecx / edx). + // + // For AND/OR/XOR we need to use a CMPXCHG loop: + // + // movl *mem, eax + // L: mov eax, temp + // andl value, temp + // lock cmpxchg temp, mem ; reads eax also + // jnz L + // ; result in eax + // + // Note the placement of L, cmpxchg will update eax with *mem if + // *mem does not have the expected value, so reloading it at the + // top of the loop would be redundant. + // + // We want to fix eax as the output. We also need a temp for + // the intermediate value. + // + // For the 8-bit variants the temp must have a byte register. + // + // There are optimization opportunities: + // - when the result is unused, Bug #1077014. + // - better register allocation and instruction selection, Bug #1077036. + + bool bitOp = !(ins->operation() == AtomicFetchAddOp || ins->operation() == AtomicFetchSubOp); + LDefinition tempDef = LDefinition::BogusTemp(); + LAllocation value; + + // Optimization opportunity: "value" need not be pinned to something that + // has a byte register unless the back-end insists on using a byte move + // for the setup or the payload computation, which really it need not do. + + if (byteArray) { + value = useFixed(ins->value(), ebx); + if (bitOp) + tempDef = tempFixed(ecx); + } else { + value = useRegister(ins->value()); + if (bitOp) + tempDef = temp(); + } + + LAsmJSAtomicBinopHeap *lir = + new(alloc()) LAsmJSAtomicBinopHeap(useRegister(ptr), value, tempDef); + + lir->setAddrTemp(temp()); + defineFixed(lir, ins, LAllocation(AnyRegister(eax))); } void diff --git a/js/src/jit/x86/Lowering-x86.h b/js/src/jit/x86/Lowering-x86.h index 7c62309b119a..2ea268982fb6 100644 --- a/js/src/jit/x86/Lowering-x86.h +++ b/js/src/jit/x86/Lowering-x86.h @@ -48,6 +48,8 @@ class LIRGeneratorX86 : public LIRGeneratorX86Shared void visitBox(MBox *box); void visitUnbox(MUnbox *unbox); void visitReturn(MReturn *ret); + void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement *ins); + void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop *ins); void visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins); void visitAsmJSUnsignedToFloat32(MAsmJSUnsignedToFloat32 *ins); void visitAsmJSLoadHeap(MAsmJSLoadHeap *ins); diff --git a/js/src/jsmath.cpp b/js/src/jsmath.cpp index 400de4100e76..379381b8ce71 100644 --- a/js/src/jsmath.cpp +++ b/js/src/jsmath.cpp @@ -35,6 +35,12 @@ #include "jsobjinlines.h" +#if defined(ANDROID) || defined(XP_MACOSX) || defined(__DragonFly__) || \ + defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +# include +# define HAVE_ARC4RANDOM +#endif + using namespace js; using mozilla::Abs; @@ -739,11 +745,10 @@ random_generateSeed() error = rand_s(&seed.u32[1]); MOZ_ASSERT(error == 0, "rand_s() error?!"); +#elif defined(HAVE_ARC4RANDOM) + seed.u32[0] = arc4random(); + seed.u32[1] = arc4random(); #elif defined(XP_UNIX) - /* - * In the unlikely event we can't read /dev/urandom, there's not much we can - * do, so just mix in the fd error code and the current time. - */ int fd = open("/dev/urandom", O_RDONLY); MOZ_ASSERT(fd >= 0, "Can't open /dev/urandom?!"); if (fd >= 0) { @@ -752,7 +757,6 @@ random_generateSeed() mozilla::unused << nread; close(fd); } - seed.u32[0] ^= fd; #else # error "Platform needs to implement random_generateSeed()" #endif diff --git a/js/src/vm/SavedStacks.h b/js/src/vm/SavedStacks.h index da820230aa1a..6d8f9b2ce615 100644 --- a/js/src/vm/SavedStacks.h +++ b/js/src/vm/SavedStacks.h @@ -132,10 +132,6 @@ class SavedStacks { : frames(), allocationSamplingProbability(1.0), allocationSkipCount(0), - // XXX: Initialize the RNG state to 0 so that random_initSeed is lazily - // called for us on the first call to random_next (via - // random_nextDouble). We need to do this here because /dev/urandom - // doesn't exist on Android, resulting in assertion failures. rngState(0) { } diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp index d2a33ee2719e..4596afccdf20 100644 --- a/js/src/vm/StructuredClone.cpp +++ b/js/src/vm/StructuredClone.cpp @@ -1216,7 +1216,7 @@ JSStructuredCloneWriter::write(HandleValue v) entries.popBack(); checkStack(); - if (obj->is()) { + if (ObjectClassIs(obj, ESClass_Map, context())) { counts.back()--; RootedValue val(context(), entries.back()); entries.popBack(); @@ -1224,7 +1224,7 @@ JSStructuredCloneWriter::write(HandleValue v) if (!startWrite(key) || !startWrite(val)) return false; - } else if (obj->is()) { + } else if (ObjectClassIs(obj, ESClass_Set, context())) { if (!startWrite(key)) return false; } else { diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index 407876e5d51e..9988a7c51f63 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -2172,12 +2172,8 @@ nsPresContext::UserFontSetUpdated(gfxUserFontEntry* aUpdatedFont) // depend upon font metrics. Updating this information requires // rebuilding the rule tree from the top, avoiding the reuse of cached // data even when no style rules have changed. - if (UsesExChUnits()) { - // xxx - dbaron said this should work but get ex/ch related reftest failures - // PostRebuildAllStyleDataEvent(nsChangeHint(0), eRestyle_ForceDescendants); - PostRebuildAllStyleDataEvent(NS_STYLE_HINT_REFLOW, eRestyle_ForceDescendants); - return; + PostRebuildAllStyleDataEvent(nsChangeHint(0), eRestyle_ForceDescendants); } // Iterate over the frame tree looking for frames associated with the diff --git a/layout/generic/nsSelection.cpp b/layout/generic/nsSelection.cpp index 99b01f88c153..c82e5f004439 100644 --- a/layout/generic/nsSelection.cpp +++ b/layout/generic/nsSelection.cpp @@ -6125,5 +6125,6 @@ nsAutoCopyListener::NotifySelectionChanged(nsIDOMDocument *aDoc, NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); // call the copy code - return nsCopySupport::HTMLCopy(aSel, doc, nsIClipboard::kSelectionClipboard); + return nsCopySupport::HTMLCopy(aSel, doc, + nsIClipboard::kSelectionClipboard, false); } diff --git a/layout/media/moz.build b/layout/media/moz.build index c494ec51ece9..deef25e09780 100644 --- a/layout/media/moz.build +++ b/layout/media/moz.build @@ -10,7 +10,6 @@ with Files('**'): if CONFIG['GKMEDIAS_SHARED_LIBRARY']: GeckoSharedLibrary('gkmedias', linkage=None) USE_LIBS += [ - 'mozalloc', 'nspr', ] else: diff --git a/media/gmp-clearkey/0.1/ClearKeyBase64.cpp b/media/gmp-clearkey/0.1/ClearKeyBase64.cpp new file mode 100644 index 000000000000..1afa4200ff63 --- /dev/null +++ b/media/gmp-clearkey/0.1/ClearKeyBase64.cpp @@ -0,0 +1,82 @@ +/* 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 "ClearKeyBase64.h" + +#include + +#include "mozilla/ArrayUtils.h" + +using namespace std; + +/** +* Take a base64-encoded string, convert (in-place) each character to its +* corresponding value in the [0x00, 0x3f] range, and truncate any padding. +*/ +static bool +Decode6Bit(string& aStr) +{ + for (size_t i = 0; i < aStr.length(); i++) { + if (aStr[i] >= 'A' && aStr[i] <= 'Z') { + aStr[i] -= 'A'; + } + else if (aStr[i] >= 'a' && aStr[i] <= 'z') { + aStr[i] -= 'a' - 26; + } + else if (aStr[i] >= '0' && aStr[i] <= '9') { + aStr[i] -= '0' - 52; + } + else if (aStr[i] == '-' || aStr[i] == '+') { + aStr[i] = 62; + } + else if (aStr[i] == '_' || aStr[i] == '/') { + aStr[i] = 63; + } + else { + // Truncate '=' padding at the end of the aString. + if (aStr[i] != '=') { + aStr.erase(i, string::npos); + return false; + } + aStr[i] = '\0'; + aStr.resize(i); + break; + } + } + + return true; +} + +bool +DecodeBase64KeyOrId(const string& aEncoded, vector& aOutDecoded) +{ + string encoded = aEncoded; + if (!Decode6Bit(encoded) || + encoded.size() != 22) { // Can't decode to 16 byte CENC key or keyId. + return false; + } + + // The number of bytes we haven't yet filled in the current byte, mod 8. + int shift = 0; + + aOutDecoded.resize(16); + vector::iterator out = aOutDecoded.begin(); + for (size_t i = 0; i < encoded.length(); i++) { + if (!shift) { + *out = encoded[i] << 2; + } + else { + *out |= encoded[i] >> (6 - shift); + out++; + if (out == aOutDecoded.end()) { + // Hit last 6bit octed in encoded, which is padding and can be ignored. + break; + } + *out = encoded[i] << (shift + 2); + } + shift = (shift + 2) % 8; + } + + return true; +} \ No newline at end of file diff --git a/media/gmp-clearkey/0.1/ClearKeyBase64.h b/media/gmp-clearkey/0.1/ClearKeyBase64.h new file mode 100644 index 000000000000..3e86d554275c --- /dev/null +++ b/media/gmp-clearkey/0.1/ClearKeyBase64.h @@ -0,0 +1,19 @@ +/* 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 __ClearKeyBase64_h__ +#define __ClearKeyBase64_h__ + +#include +#include +#include + +// Decodes a base64 encoded CENC Key or KeyId into it's raw bytes. Note that +// CENC Keys or KeyIds are 16 bytes long, so encoded they should be 22 bytes +// plus any padding. Fails (returns false) on input that is more than 22 bytes +// long after padding is stripped. Returns true on success. +bool +DecodeBase64KeyOrId(const std::string& aEncoded, std::vector& aOutDecoded); + +#endif diff --git a/media/gmp-clearkey/0.1/ClearKeyUtils.cpp b/media/gmp-clearkey/0.1/ClearKeyUtils.cpp index f7b77e43860b..3d7e58406da6 100644 --- a/media/gmp-clearkey/0.1/ClearKeyUtils.cpp +++ b/media/gmp-clearkey/0.1/ClearKeyUtils.cpp @@ -9,6 +9,7 @@ #include #include "ClearKeyUtils.h" +#include "ClearKeyBase64.h" #include "mozilla/ArrayUtils.h" #include "mozilla/Assertions.h" #include "mozilla/Endian.h" @@ -362,69 +363,6 @@ GetNextLabel(ParserContext& aCtx, string& aOutLabel) return false; } -/** - * Take a base64-encoded string, convert (in-place) each character to its - * corresponding value in the [0x00, 0x3f] range, and truncate any padding. - */ -static bool -Decode6Bit(string& aStr) -{ - for (size_t i = 0; i < aStr.length(); i++) { - if (aStr[i] >= 'A' && aStr[i] <= 'Z') { - aStr[i] -= 'A'; - } else if (aStr[i] >= 'a' && aStr[i] <= 'z') { - aStr[i] -= 'a' - 26; - } else if (aStr[i] >= '0' && aStr[i] <= '9') { - aStr[i] -= '0' - 52; - } else if (aStr[i] == '-' || aStr[i] == '+') { - aStr[i] = 62; - } else if (aStr[i] == '_' || aStr[i] == '/') { - aStr[i] = 63; - } else { - // Truncate '=' padding at the end of the aString. - if (aStr[i] != '=') { - return false; - } - aStr[i] = '\0'; - aStr.resize(i); - break; - } - } - - return true; -} - -static bool -DecodeBase64KeyOrId(string& aEncoded, vector& aOutDecoded) -{ - if (aEncoded.size() != 22 || // Can't decode to 16 byte CENC key or keyId. - !Decode6Bit(aEncoded)) { - return false; - } - - // The number of bytes we haven't yet filled in the current byte, mod 8. - int shift = 0; - - aOutDecoded.resize(16); - vector::iterator out = aOutDecoded.begin(); - for (size_t i = 0; i < aEncoded.length(); i++) { - if (!shift) { - *out = aEncoded[i] << 2; - } else { - *out |= aEncoded[i] >> (6 - shift); - out++; - if (out == aOutDecoded.end()) { - // Hit last 6bit octed in encoded, which is padding and can be ignored. - break; - } - *out = aEncoded[i] << (shift + 2); - } - shift = (shift + 2) % 8; - } - - return true; -} - static bool DecodeKey(string& aEncoded, Key& aOutDecoded) { diff --git a/media/gmp-clearkey/0.1/gtest/TestClearKeyUtils.cpp b/media/gmp-clearkey/0.1/gtest/TestClearKeyUtils.cpp new file mode 100644 index 000000000000..865a225b1f94 --- /dev/null +++ b/media/gmp-clearkey/0.1/gtest/TestClearKeyUtils.cpp @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "gtest/gtest.h" +#include +#include +#include + +#include "../ClearKeyBase64.cpp" + + +using namespace std; +using namespace mozilla; + +struct B64Test { + const char* b64; + uint8_t raw[16]; + bool shouldPass; +}; + +B64Test tests[] = { + { + "AAAAADk4AU4AAAAAAAAAAA", + { 0x0, 0x0, 0x0, 0x0, 0x39, 0x38, 0x1, 0x4e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, + true + }, + { + "h2mqp1zAJjDIC34YXEXBxA==", + { 0x87, 0x69, 0xaa, 0xa7, 0x5c, 0xc0, 0x26, 0x30, 0xc8, 0xb, 0x7e, 0x18, 0x5c, 0x45, 0xc1, 0xc4 }, + true + }, + { + "flcdA35XHQN-Vx0DflcdAw", + { 0x7e, 0x57, 0x1d, 0x3, 0x7e, 0x57, 0x1d, 0x3, 0x7e, 0x57, 0x1d, 0x3, 0x7e, 0x57, 0x1d, 0x3 }, + true + }, + { + "flczM35XMzN-VzMzflczMw", + { 0x7e, 0x57, 0x33, 0x33, 0x7e, 0x57, 0x33, 0x33, 0x7e, 0x57, 0x33, 0x33, 0x7e, 0x57, 0x33, 0x33 }, + true + }, + { + "flcdBH5XHQR-Vx0EflcdBA", + { 0x7e, 0x57, 0x1d, 0x4, 0x7e, 0x57, 0x1d, 0x4, 0x7e, 0x57, 0x1d, 0x4, 0x7e, 0x57, 0x1d, 0x4 }, + true + }, + { + "fldERH5XRER-V0REfldERA", + { 0x7e, 0x57, 0x44, 0x44, 0x7e, 0x57, 0x44, 0x44, 0x7e, 0x57, 0x44, 0x44, 0x7e, 0x57, 0x44, 0x44 }, + true + }, + // Failure tests + { "", { 0 }, false }, // empty + { "fuzzbiz", { 0 }, false }, // Too short + { "fuzzbizfuzzbizfuzzbizfuzzbizfuzzbizfuzzbizfuzzbizfuzzbiz", { 0 }, false }, // too long + +}; + +TEST(ClearKey, DecodeBase64KeyOrId) { + for (size_t i = 0; i < MOZ_ARRAY_LENGTH(tests); i++) { + vector v; + const B64Test& test = tests[i]; + bool rv = DecodeBase64KeyOrId(string(test.b64), v); + EXPECT_EQ(rv, test.shouldPass); + if (test.shouldPass) { + EXPECT_EQ(v.size(), 16u); + for (size_t k = 0; k < 16; k++) { + EXPECT_EQ(v[k], test.raw[k]); + } + } + } +} diff --git a/media/gmp-clearkey/0.1/gtest/moz.build b/media/gmp-clearkey/0.1/gtest/moz.build new file mode 100644 index 000000000000..c46b68defe0f --- /dev/null +++ b/media/gmp-clearkey/0.1/gtest/moz.build @@ -0,0 +1,17 @@ +# -*- 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 += [ + 'TestClearKeyUtils.cpp', +] + +FINAL_LIBRARY = 'xul-gtest' + +FAIL_ON_WARNINGS = True + +LOCAL_INCLUDES += [ + '..', +] diff --git a/media/gmp-clearkey/0.1/moz.build b/media/gmp-clearkey/0.1/moz.build index 2de2811567fd..03724b99b2b3 100644 --- a/media/gmp-clearkey/0.1/moz.build +++ b/media/gmp-clearkey/0.1/moz.build @@ -9,6 +9,7 @@ SharedLibrary('clearkey') FINAL_TARGET = 'dist/bin/gmp-clearkey/0.1' UNIFIED_SOURCES += [ + 'ClearKeyBase64.cpp', 'ClearKeyDecryptionManager.cpp', 'ClearKeyPersistence.cpp', 'ClearKeySession.cpp', @@ -41,6 +42,10 @@ if CONFIG['OS_ARCH'] == 'WINNT': DEFINES['ENABLE_WMF'] = True +TEST_DIRS += [ + 'gtest', +] + LOCAL_INCLUDES += [ '/dom/media/gmp', diff --git a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp index 4ea4d8d58eac..6734fcfb0c76 100644 --- a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp +++ b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp @@ -450,7 +450,7 @@ WebrtcGmpVideoEncoder::Encoded(GMPVideoEncodedFrame* aEncodedFrame, uint32_t offset; uint32_t size; }; - nsTArray nals; + nsAutoTArray nals; uint32_t size; // make sure we don't read past the end of the buffer getting the size while (buffer+size_bytes < end) { diff --git a/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.cpp b/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.cpp index fd296b29ede7..9d24fea36074 100644 --- a/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.cpp +++ b/media/webrtc/signaling/src/media-conduit/WebrtcOMXH264VideoCodec.cpp @@ -749,29 +749,47 @@ private: void SendEncodedDataToCallback(webrtc::EncodedImage& aEncodedImage, bool aPrependParamSets) { - // Individual NALU inherits metadata from input encoded data. - webrtc::EncodedImage nalu(aEncodedImage); - if (aPrependParamSets) { + webrtc::EncodedImage prepend(aEncodedImage); // Insert current parameter sets in front of the input encoded data. MOZ_ASSERT(mParamSets.Length() > sizeof(kNALStartCode)); // Start code + ... - nalu._length = mParamSets.Length(); - nalu._buffer = mParamSets.Elements(); + prepend._length = mParamSets.Length(); + prepend._buffer = mParamSets.Elements(); // Break into NALUs and send. CODEC_LOGD("Prepending SPS/PPS: %d bytes, timestamp %u, captureTimeMs %" PRIu64, - nalu._length, nalu._timeStamp, nalu.capture_time_ms_); - SendEncodedDataToCallback(nalu, false); + prepend._length, prepend._timeStamp, prepend.capture_time_ms_); + SendEncodedDataToCallback(prepend, false); } + struct nal_entry { + uint32_t offset; + uint32_t size; + }; + nsAutoTArray nals; + // Break input encoded data into NALUs and send each one to callback. const uint8_t* data = aEncodedImage._buffer; size_t size = aEncodedImage._length; const uint8_t* nalStart = nullptr; size_t nalSize = 0; while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) { - nalu._buffer = const_cast(nalStart); - nalu._length = nalSize; - mCallback->Encoded(nalu, nullptr, nullptr); + // XXX optimize by making buffer an offset + nal_entry nal = {((uint32_t) (nalStart - aEncodedImage._buffer)), (uint32_t) nalSize}; + nals.AppendElement(nal); + } + + size_t num_nals = nals.Length(); + if (num_nals > 0) { + webrtc::RTPFragmentationHeader fragmentation; + fragmentation.VerifyAndAllocateFragmentationHeader(num_nals); + for (size_t i = 0; i < num_nals; i++) { + fragmentation.fragmentationOffset[i] = nals[i].offset; + fragmentation.fragmentationLength[i] = nals[i].size; + } + webrtc::EncodedImage unit(aEncodedImage); + unit._completeFrame = true; + + mCallback->Encoded(unit, nullptr, &fragmentation); } } diff --git a/memory/jemalloc/0008-Make-without-export-actually-work.patch b/memory/jemalloc/0008-Make-without-export-actually-work.patch new file mode 100644 index 000000000000..774982848526 --- /dev/null +++ b/memory/jemalloc/0008-Make-without-export-actually-work.patch @@ -0,0 +1,60 @@ +From 7c46fd59cce6afb14cdc6c819f662b6e81638f84 Mon Sep 17 00:00:00 2001 +From: Mike Hommey +Date: Wed, 4 Mar 2015 21:48:01 +0900 +Subject: [PATCH] Make --without-export actually work + +9906660 added a --without-export configure option to avoid exporting +jemalloc symbols, but the option didn't actually work. +--- + include/jemalloc/internal/jemalloc_internal_defs.h.in | 6 ++++++ + include/jemalloc/jemalloc_macros.h.in | 14 +++++++++----- + 2 files changed, 15 insertions(+), 5 deletions(-) + +diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in +index 0f0db8a..191abc5 100644 +--- a/include/jemalloc/internal/jemalloc_internal_defs.h.in ++++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in +@@ -232,4 +232,10 @@ + /* Adaptive mutex support in pthreads. */ + #undef JEMALLOC_HAVE_PTHREAD_MUTEX_ADAPTIVE_NP + ++/* ++ * If defined, jemalloc symbols are not exported (doesn't work when ++ * JEMALLOC_PREFIX is not defined). ++ */ ++#undef JEMALLOC_EXPORT ++ + #endif /* JEMALLOC_INTERNAL_DEFS_H_ */ +diff --git a/include/jemalloc/jemalloc_macros.h.in b/include/jemalloc/jemalloc_macros.h.in +index 7d1dcf4..72f2a08 100644 +--- a/include/jemalloc/jemalloc_macros.h.in ++++ b/include/jemalloc/jemalloc_macros.h.in +@@ -32,16 +32,20 @@ + + #ifdef JEMALLOC_HAVE_ATTR + # define JEMALLOC_ATTR(s) __attribute__((s)) +-# define JEMALLOC_EXPORT JEMALLOC_ATTR(visibility("default")) ++# ifndef JEMALLOC_EXPORT ++# define JEMALLOC_EXPORT JEMALLOC_ATTR(visibility("default")) ++# endif + # define JEMALLOC_ALIGNED(s) JEMALLOC_ATTR(aligned(s)) + # define JEMALLOC_SECTION(s) JEMALLOC_ATTR(section(s)) + # define JEMALLOC_NOINLINE JEMALLOC_ATTR(noinline) + #elif _MSC_VER + # define JEMALLOC_ATTR(s) +-# ifdef DLLEXPORT +-# define JEMALLOC_EXPORT __declspec(dllexport) +-# else +-# define JEMALLOC_EXPORT __declspec(dllimport) ++# ifndef JEMALLOC_EXPORT ++# ifdef DLLEXPORT ++# define JEMALLOC_EXPORT __declspec(dllexport) ++# else ++# define JEMALLOC_EXPORT __declspec(dllimport) ++# endif + # endif + # define JEMALLOC_ALIGNED(s) __declspec(align(s)) + # define JEMALLOC_SECTION(s) __declspec(allocate(s)) +-- +2.3.0.4.g34b1174 + diff --git a/memory/jemalloc/src/include/jemalloc/internal/jemalloc_internal_defs.h.in b/memory/jemalloc/src/include/jemalloc/internal/jemalloc_internal_defs.h.in index c8d7dafbaa4e..a943d23c961b 100644 --- a/memory/jemalloc/src/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/memory/jemalloc/src/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -238,4 +238,10 @@ /* Adaptive mutex support in pthreads. */ #undef JEMALLOC_HAVE_PTHREAD_MUTEX_ADAPTIVE_NP +/* + * If defined, jemalloc symbols are not exported (doesn't work when + * JEMALLOC_PREFIX is not defined). + */ +#undef JEMALLOC_EXPORT + #endif /* JEMALLOC_INTERNAL_DEFS_H_ */ diff --git a/memory/jemalloc/src/include/jemalloc/jemalloc_macros.h.in b/memory/jemalloc/src/include/jemalloc/jemalloc_macros.h.in index 99f12611d6bf..0c1ff7794b1e 100644 --- a/memory/jemalloc/src/include/jemalloc/jemalloc_macros.h.in +++ b/memory/jemalloc/src/include/jemalloc/jemalloc_macros.h.in @@ -24,16 +24,20 @@ #ifdef JEMALLOC_HAVE_ATTR # define JEMALLOC_ATTR(s) __attribute__((s)) -# define JEMALLOC_EXPORT JEMALLOC_ATTR(visibility("default")) +# ifndef JEMALLOC_EXPORT +# define JEMALLOC_EXPORT JEMALLOC_ATTR(visibility("default")) +# endif # define JEMALLOC_ALIGNED(s) JEMALLOC_ATTR(aligned(s)) # define JEMALLOC_SECTION(s) JEMALLOC_ATTR(section(s)) # define JEMALLOC_NOINLINE JEMALLOC_ATTR(noinline) #elif _MSC_VER # define JEMALLOC_ATTR(s) -# ifdef DLLEXPORT -# define JEMALLOC_EXPORT __declspec(dllexport) -# else -# define JEMALLOC_EXPORT __declspec(dllimport) +# ifndef JEMALLOC_EXPORT +# ifdef DLLEXPORT +# define JEMALLOC_EXPORT __declspec(dllexport) +# else +# define JEMALLOC_EXPORT __declspec(dllimport) +# endif # endif # define JEMALLOC_ALIGNED(s) __declspec(align(s)) # define JEMALLOC_SECTION(s) __declspec(allocate(s)) diff --git a/memory/jemalloc/update.sh b/memory/jemalloc/update.sh index ac44151b676d..4af6898f95a6 100755 --- a/memory/jemalloc/update.sh +++ b/memory/jemalloc/update.sh @@ -21,6 +21,7 @@ patch -p1 < ../0004-Implement-stats.bookkeeping.patch patch -p1 < ../0005-Bug-1121314-Avoid-needing-the-arena-in-chunk_alloc_d.patch patch -p1 < ../0006-Make-opt.lg_dirty_mult-work-as-documented.patch patch -p1 < ../0007-Preserve-LastError-when-calling-TlsGetValue.patch +patch -p1 < ../0008-Make-without-export-actually-work.patch cd .. hg addremove -q src diff --git a/memory/mozalloc/moz.build b/memory/mozalloc/moz.build index 9ccf7cb39f94..f05805a3697e 100644 --- a/memory/mozalloc/moz.build +++ b/memory/mozalloc/moz.build @@ -38,11 +38,7 @@ UNIFIED_SOURCES += [ 'mozalloc_oom.cpp', ] -if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': - Library('mozalloc') -else: - GeckoSharedLibrary('mozalloc', linkage=None) - SDK_LIBRARY = True +FINAL_LIBRARY = 'mozglue' # The strndup declaration in string.h is in an ifdef __USE_GNU section DEFINES['_GNU_SOURCE'] = True @@ -53,3 +49,8 @@ DISABLE_STL_WRAPPING = True if CONFIG['CLANG_CXX'] or CONFIG['_MSC_VER']: FAIL_ON_WARNINGS = True + +DEFINES['IMPL_MFBT'] = True + +if CONFIG['_MSC_VER']: + DIRS += ['staticruntime'] diff --git a/memory/mozalloc/mozalloc.cpp b/memory/mozalloc/mozalloc.cpp index 0ca1725131d3..b97d2017bc9e 100644 --- a/memory/mozalloc/mozalloc.cpp +++ b/memory/mozalloc/mozalloc.cpp @@ -5,33 +5,66 @@ * 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 // for size_t + +// Building with USE_STATIC_LIBS = True sets -MT instead of -MD. -MT sets _MT, +// while -MD sets _MT and _DLL. +#if defined(_MT) && !defined(_DLL) +#define MOZ_STATIC_RUNTIME +#endif + +#if defined(MOZ_MEMORY) && !defined(MOZ_STATIC_RUNTIME) +// mozalloc.cpp is part of the same library as mozmemory, thus MOZ_MEMORY_IMPL +// is needed. +#define MOZ_MEMORY_IMPL +#include "mozmemory.h" + +// See mozmemory_wrap.h for more details. This file is part of libmozglue, so +// it needs to use _impl suffixes. However, with libmozglue growing, this is +// becoming cumbersome, so we will likely use a malloc.h wrapper of some sort +// and allow the use of the functions without a _impl suffix. +#define MALLOC_DECL(name, return_type, ...) \ + extern "C" MOZ_MEMORY_API return_type name ## _impl(__VA_ARGS__); +#define MALLOC_FUNS MALLOC_FUNCS_MALLOC +#include "malloc_decls.h" + +extern "C" MOZ_MEMORY_API char *strdup_impl(const char *); +extern "C" MOZ_MEMORY_API char *strndup_impl(const char *, size_t); + +#else +// When jemalloc is disabled, or when building the static runtime variant, +// we need not to use the suffixes. + +#if defined(MALLOC_H) +# include MALLOC_H // for memalign, valloc, malloc_size, malloc_us +#endif // if defined(MALLOC_H) +#include // for malloc, free +#if defined(XP_UNIX) +# include // for valloc on *BSD +#endif //if defined(XP_UNIX) + +#define malloc_impl malloc +#define posix_memalign_impl posix_memalign +#define calloc_impl calloc +#define realloc_impl realloc +#define free_impl free +#define memalign_impl memalign +#define valloc_impl valloc +#define malloc_usable_size_impl malloc_usable_size +#define strdup_impl strdup +#define strndup_impl strndup + +#endif + #include #include // for std::bad_alloc #include #include -#if defined(MALLOC_H) -# include MALLOC_H // for memalign, valloc, malloc_size, malloc_usable_size -#endif // if defined(MALLOC_H) -#include // for size_t -#include // for malloc, free -#if defined(XP_UNIX) -# include // for valloc on *BSD -#endif //if defined(XP_UNIX) - -#if defined(XP_WIN) -# define MOZALLOC_EXPORT __declspec(dllexport) -#endif - #include "mozilla/mozalloc.h" #include "mozilla/mozalloc_oom.h" // for mozalloc_handle_oom -/* Windows doesn't have malloc_usable_size, but jemalloc has */ -#if defined(MOZ_MEMORY_WINDOWS) -extern "C" size_t malloc_usable_size(const void *ptr); -#endif - #ifdef __GNUC__ #define LIKELY(x) (__builtin_expect(!!(x), 1)) #define UNLIKELY(x) (__builtin_expect(!!(x), 0)) @@ -43,13 +76,13 @@ extern "C" size_t malloc_usable_size(const void *ptr); void moz_free(void* ptr) { - free(ptr); + free_impl(ptr); } void* moz_xmalloc(size_t size) { - void* ptr = malloc(size); + void* ptr = malloc_impl(size); if (UNLIKELY(!ptr && size)) { mozalloc_handle_oom(size); return moz_xmalloc(size); @@ -59,13 +92,13 @@ moz_xmalloc(size_t size) void* moz_malloc(size_t size) { - return malloc(size); + return malloc_impl(size); } void* moz_xcalloc(size_t nmemb, size_t size) { - void* ptr = calloc(nmemb, size); + void* ptr = calloc_impl(nmemb, size); if (UNLIKELY(!ptr && nmemb && size)) { mozalloc_handle_oom(size); return moz_xcalloc(nmemb, size); @@ -75,13 +108,13 @@ moz_xcalloc(size_t nmemb, size_t size) void* moz_calloc(size_t nmemb, size_t size) { - return calloc(nmemb, size); + return calloc_impl(nmemb, size); } void* moz_xrealloc(void* ptr, size_t size) { - void* newptr = realloc(ptr, size); + void* newptr = realloc_impl(ptr, size); if (UNLIKELY(!newptr && size)) { mozalloc_handle_oom(size); return moz_xrealloc(ptr, size); @@ -91,13 +124,13 @@ moz_xrealloc(void* ptr, size_t size) void* moz_realloc(void* ptr, size_t size) { - return realloc(ptr, size); + return realloc_impl(ptr, size); } char* moz_xstrdup(const char* str) { - char* dup = strdup(str); + char* dup = strdup_impl(str); if (UNLIKELY(!dup)) { mozalloc_handle_oom(0); return moz_xstrdup(str); @@ -107,14 +140,14 @@ moz_xstrdup(const char* str) char* moz_strdup(const char* str) { - return strdup(str); + return strdup_impl(str); } #if defined(HAVE_STRNDUP) char* moz_xstrndup(const char* str, size_t strsize) { - char* dup = strndup(str, strsize); + char* dup = strndup_impl(str, strsize); if (UNLIKELY(!dup)) { mozalloc_handle_oom(strsize); return moz_xstrndup(str, strsize); @@ -124,7 +157,7 @@ moz_xstrndup(const char* str, size_t strsize) char* moz_strndup(const char* str, size_t strsize) { - return strndup(str, strsize); + return strndup_impl(str, strsize); } #endif // if defined(HAVE_STRNDUP) @@ -132,7 +165,7 @@ moz_strndup(const char* str, size_t strsize) int moz_xposix_memalign(void **ptr, size_t alignment, size_t size) { - int err = posix_memalign(ptr, alignment, size); + int err = posix_memalign_impl(ptr, alignment, size); if (UNLIKELY(err && ENOMEM == err)) { mozalloc_handle_oom(size); return moz_xposix_memalign(ptr, alignment, size); @@ -143,7 +176,7 @@ moz_xposix_memalign(void **ptr, size_t alignment, size_t size) int moz_posix_memalign(void **ptr, size_t alignment, size_t size) { - int code = posix_memalign(ptr, alignment, size); + int code = posix_memalign_impl(ptr, alignment, size); if (code) return code; @@ -167,7 +200,7 @@ moz_posix_memalign(void **ptr, size_t alignment, size_t size) void* moz_xmemalign(size_t boundary, size_t size) { - void* ptr = memalign(boundary, size); + void* ptr = memalign_impl(boundary, size); if (UNLIKELY(!ptr && EINVAL != errno)) { mozalloc_handle_oom(size); return moz_xmemalign(boundary, size); @@ -178,7 +211,7 @@ moz_xmemalign(size_t boundary, size_t size) void* moz_memalign(size_t boundary, size_t size) { - return memalign(boundary, size); + return memalign_impl(boundary, size); } #endif // if defined(HAVE_MEMALIGN) @@ -186,7 +219,7 @@ moz_memalign(size_t boundary, size_t size) void* moz_xvalloc(size_t size) { - void* ptr = valloc(size); + void* ptr = valloc_impl(size); if (UNLIKELY(!ptr)) { mozalloc_handle_oom(size); return moz_xvalloc(size); @@ -196,10 +229,11 @@ moz_xvalloc(size_t size) void* moz_valloc(size_t size) { - return valloc(size); + return valloc_impl(size); } #endif // if defined(HAVE_VALLOC) +#if !(defined(_MT) && !defined(_DLL)) size_t moz_malloc_usable_size(void *ptr) { @@ -209,7 +243,7 @@ moz_malloc_usable_size(void *ptr) #if defined(XP_MACOSX) return malloc_size(ptr); #elif defined(HAVE_MALLOC_USABLE_SIZE) || defined(MOZ_MEMORY) - return malloc_usable_size(ptr); + return malloc_usable_size_impl(ptr); #elif defined(XP_WIN) return _msize(ptr); #else @@ -221,3 +255,4 @@ size_t moz_malloc_size_of(const void *ptr) { return moz_malloc_usable_size((void *)ptr); } +#endif diff --git a/memory/mozalloc/mozalloc.h b/memory/mozalloc/mozalloc.h index 2b370ec25229..d62e984231cf 100644 --- a/memory/mozalloc/mozalloc.h +++ b/memory/mozalloc/mozalloc.h @@ -24,23 +24,10 @@ #include "mozilla/TemplateLib.h" #endif #include "mozilla/Attributes.h" +#include "mozilla/Types.h" #define MOZALLOC_HAVE_XMALLOC -#if defined(MOZALLOC_EXPORT) -/* do nothing: it's been defined to __declspec(dllexport) by - * mozalloc*.cpp on platforms where that's required. */ -#elif defined(XP_WIN) -# define MOZALLOC_EXPORT __declspec(dllimport) -#elif defined(HAVE_VISIBILITY_ATTRIBUTE) -/* Make sure symbols are still exported even if we're wrapped in a - * |visibility push(hidden)| blanket. */ -# define MOZALLOC_EXPORT __attribute__ ((visibility ("default"))) -#else -# define MOZALLOC_EXPORT -#endif - - #if defined(MOZ_ALWAYS_INLINE_EVEN_DEBUG) # define MOZALLOC_INLINE MOZ_ALWAYS_INLINE_EVEN_DEBUG #elif defined(HAVE_FORCEINLINE) @@ -75,73 +62,73 @@ extern "C" { * passing that pointer to |moz_free()|. */ -MOZALLOC_EXPORT +MFBT_API void moz_free(void* ptr); -MOZALLOC_EXPORT void* moz_xmalloc(size_t size) +MFBT_API void* moz_xmalloc(size_t size) NS_ATTR_MALLOC NS_WARN_UNUSED_RESULT; -MOZALLOC_EXPORT +MFBT_API void* moz_malloc(size_t size) NS_ATTR_MALLOC NS_WARN_UNUSED_RESULT; -MOZALLOC_EXPORT void* moz_xcalloc(size_t nmemb, size_t size) +MFBT_API void* moz_xcalloc(size_t nmemb, size_t size) NS_ATTR_MALLOC NS_WARN_UNUSED_RESULT; -MOZALLOC_EXPORT void* moz_calloc(size_t nmemb, size_t size) +MFBT_API void* moz_calloc(size_t nmemb, size_t size) NS_ATTR_MALLOC NS_WARN_UNUSED_RESULT; -MOZALLOC_EXPORT void* moz_xrealloc(void* ptr, size_t size) +MFBT_API void* moz_xrealloc(void* ptr, size_t size) NS_ATTR_MALLOC NS_WARN_UNUSED_RESULT; -MOZALLOC_EXPORT void* moz_realloc(void* ptr, size_t size) +MFBT_API void* moz_realloc(void* ptr, size_t size) NS_ATTR_MALLOC NS_WARN_UNUSED_RESULT; -MOZALLOC_EXPORT char* moz_xstrdup(const char* str) +MFBT_API char* moz_xstrdup(const char* str) NS_ATTR_MALLOC NS_WARN_UNUSED_RESULT; -MOZALLOC_EXPORT char* moz_strdup(const char* str) +MFBT_API char* moz_strdup(const char* str) NS_ATTR_MALLOC NS_WARN_UNUSED_RESULT; -MOZALLOC_EXPORT size_t moz_malloc_usable_size(void *ptr); +MFBT_API size_t moz_malloc_usable_size(void *ptr); -MOZALLOC_EXPORT size_t moz_malloc_size_of(const void *ptr); +MFBT_API size_t moz_malloc_size_of(const void *ptr); #if defined(HAVE_STRNDUP) -MOZALLOC_EXPORT char* moz_xstrndup(const char* str, size_t strsize) +MFBT_API char* moz_xstrndup(const char* str, size_t strsize) NS_ATTR_MALLOC NS_WARN_UNUSED_RESULT; -MOZALLOC_EXPORT char* moz_strndup(const char* str, size_t strsize) +MFBT_API char* moz_strndup(const char* str, size_t strsize) NS_ATTR_MALLOC NS_WARN_UNUSED_RESULT; #endif /* if defined(HAVE_STRNDUP) */ #if defined(HAVE_POSIX_MEMALIGN) -MOZALLOC_EXPORT int moz_xposix_memalign(void **ptr, size_t alignment, size_t size) +MFBT_API int moz_xposix_memalign(void **ptr, size_t alignment, size_t size) NS_WARN_UNUSED_RESULT; -MOZALLOC_EXPORT int moz_posix_memalign(void **ptr, size_t alignment, size_t size) +MFBT_API int moz_posix_memalign(void **ptr, size_t alignment, size_t size) NS_WARN_UNUSED_RESULT; #endif /* if defined(HAVE_POSIX_MEMALIGN) */ #if defined(HAVE_MEMALIGN) -MOZALLOC_EXPORT void* moz_xmemalign(size_t boundary, size_t size) +MFBT_API void* moz_xmemalign(size_t boundary, size_t size) NS_ATTR_MALLOC NS_WARN_UNUSED_RESULT; -MOZALLOC_EXPORT void* moz_memalign(size_t boundary, size_t size) +MFBT_API void* moz_memalign(size_t boundary, size_t size) NS_ATTR_MALLOC NS_WARN_UNUSED_RESULT; #endif /* if defined(HAVE_MEMALIGN) */ #if defined(HAVE_VALLOC) -MOZALLOC_EXPORT void* moz_xvalloc(size_t size) +MFBT_API void* moz_xvalloc(size_t size) NS_ATTR_MALLOC NS_WARN_UNUSED_RESULT; -MOZALLOC_EXPORT void* moz_valloc(size_t size) +MFBT_API void* moz_valloc(size_t size) NS_ATTR_MALLOC NS_WARN_UNUSED_RESULT; #endif /* if defined(HAVE_VALLOC) */ @@ -176,7 +163,7 @@ MOZALLOC_EXPORT void* moz_valloc(size_t size) * visibility on OS X/gcc. These symbols are force-inline and not * exported. */ #if defined(XP_MACOSX) -# define MOZALLOC_EXPORT_NEW MOZALLOC_EXPORT +# define MOZALLOC_EXPORT_NEW MFBT_API #else # define MOZALLOC_EXPORT_NEW #endif diff --git a/memory/mozalloc/mozalloc_abort.cpp b/memory/mozalloc/mozalloc_abort.cpp index 5b4f74012a39..cb619d190978 100644 --- a/memory/mozalloc/mozalloc_abort.cpp +++ b/memory/mozalloc/mozalloc_abort.cpp @@ -5,10 +5,6 @@ * 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(XP_WIN) -# define MOZALLOC_EXPORT __declspec(dllexport) -#endif - #include "mozilla/mozalloc_abort.h" #ifdef ANDROID diff --git a/memory/mozalloc/mozalloc_abort.h b/memory/mozalloc/mozalloc_abort.h index bf9d73c89439..065cebcb31cd 100644 --- a/memory/mozalloc/mozalloc_abort.h +++ b/memory/mozalloc/mozalloc_abort.h @@ -9,19 +9,7 @@ #define mozilla_mozalloc_abort_h #include "mozilla/Attributes.h" - -#if defined(MOZALLOC_EXPORT) -// do nothing: it's been defined to __declspec(dllexport) by -// mozalloc*.cpp on platforms where that's required -#elif defined(XP_WIN) -# define MOZALLOC_EXPORT __declspec(dllimport) -#elif defined(HAVE_VISIBILITY_ATTRIBUTE) -/* Make sure symbols are still exported even if we're wrapped in a - * |visibility push(hidden)| blanket. */ -# define MOZALLOC_EXPORT __attribute__ ((visibility ("default"))) -#else -# define MOZALLOC_EXPORT -#endif +#include "mozilla/Types.h" /** * Terminate this process in such a way that breakpad is triggered, if @@ -30,7 +18,7 @@ * Note: MOZ_NORETURN seems to break crash stacks on ARM, so we don't * use that annotation there. */ -MOZALLOC_EXPORT +MFBT_API #if !defined(__arm__) MOZ_NORETURN #endif diff --git a/memory/mozalloc/mozalloc_oom.cpp b/memory/mozalloc/mozalloc_oom.cpp index d1229d417462..820888cdbfad 100644 --- a/memory/mozalloc/mozalloc_oom.cpp +++ b/memory/mozalloc/mozalloc_oom.cpp @@ -5,10 +5,6 @@ * 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(XP_WIN) -# define MOZALLOC_EXPORT __declspec(dllexport) -#endif - #include "mozilla/mozalloc_abort.h" #include "mozilla/mozalloc_oom.h" #include "mozilla/Assertions.h" diff --git a/memory/mozalloc/mozalloc_oom.h b/memory/mozalloc/mozalloc_oom.h index bd3daec08848..35bb9acc8773 100644 --- a/memory/mozalloc/mozalloc_oom.h +++ b/memory/mozalloc/mozalloc_oom.h @@ -10,28 +10,11 @@ #include "mozalloc.h" -#if defined(MOZALLOC_EXPORT) -// do nothing: it's been defined to __declspec(dllexport) by -// mozalloc*.cpp on platforms where that's required -#elif defined(XP_WIN) -# define MOZALLOC_EXPORT __declspec(dllimport) -#elif defined(HAVE_VISIBILITY_ATTRIBUTE) -/* Make sure symbols are still exported even if we're wrapped in a - * |visibility push(hidden)| blanket. */ -# define MOZALLOC_EXPORT __attribute__ ((visibility ("default"))) -#else -# define MOZALLOC_EXPORT -#endif - - /** - * Called when memory is critically low. Returns iff it was able to + * Called when memory is critically low. Returns iff it was able to * remedy the critical memory situation; if not, it will abort(). - * - * We have to re-#define MOZALLOC_EXPORT because this header can be - * used indepedently of mozalloc.h. */ -MOZALLOC_EXPORT void mozalloc_handle_oom(size_t requestedSize); +MFBT_API void mozalloc_handle_oom(size_t requestedSize); /** * Called by embedders (specifically Mozilla breakpad) which wants to be @@ -39,7 +22,7 @@ MOZALLOC_EXPORT void mozalloc_handle_oom(size_t requestedSize); * the size of the allocation on which we aborted. */ typedef void (*mozalloc_oom_abort_handler)(size_t size); -MOZALLOC_EXPORT void mozalloc_set_oom_abort_handler(mozalloc_oom_abort_handler handler); +MFBT_API void mozalloc_set_oom_abort_handler(mozalloc_oom_abort_handler handler); /* TODO: functions to query system memory usage and register * critical-memory handlers. */ diff --git a/memory/mozalloc/msvc_raise_wrappers.cpp b/memory/mozalloc/msvc_raise_wrappers.cpp index 1675f96ca667..09186714d2ab 100644 --- a/memory/mozalloc/msvc_raise_wrappers.cpp +++ b/memory/mozalloc/msvc_raise_wrappers.cpp @@ -7,10 +7,6 @@ #include -#if defined(XP_WIN) -# define MOZALLOC_EXPORT __declspec(dllexport) -#endif - #include "mozalloc_abort.h" #define MOZALLOC_DONT_WRAP_RAISE_FUNCTIONS diff --git a/memory/mozalloc/msvc_raise_wrappers.h b/memory/mozalloc/msvc_raise_wrappers.h index 98e233bbad07..557a481ea4e1 100644 --- a/memory/mozalloc/msvc_raise_wrappers.h +++ b/memory/mozalloc/msvc_raise_wrappers.h @@ -23,11 +23,11 @@ namespace std { // doing this after careful review because we want to define our own // exception throwing semantics. Don't try this at home! -MOZALLOC_EXPORT __declspec(noreturn) void moz_Xinvalid_argument(const char*); -MOZALLOC_EXPORT __declspec(noreturn) void moz_Xlength_error(const char*); -MOZALLOC_EXPORT __declspec(noreturn) void moz_Xout_of_range(const char*); -MOZALLOC_EXPORT __declspec(noreturn) void moz_Xoverflow_error(const char*); -MOZALLOC_EXPORT __declspec(noreturn) void moz_Xruntime_error(const char*); +MFBT_API __declspec(noreturn) void moz_Xinvalid_argument(const char*); +MFBT_API __declspec(noreturn) void moz_Xlength_error(const char*); +MFBT_API __declspec(noreturn) void moz_Xout_of_range(const char*); +MFBT_API __declspec(noreturn) void moz_Xoverflow_error(const char*); +MFBT_API __declspec(noreturn) void moz_Xruntime_error(const char*); } // namespace std diff --git a/memory/mozalloc/msvc_throw_wrapper.cpp b/memory/mozalloc/msvc_throw_wrapper.cpp index 14c3692b1741..52ca221f1b96 100644 --- a/memory/mozalloc/msvc_throw_wrapper.cpp +++ b/memory/mozalloc/msvc_throw_wrapper.cpp @@ -7,10 +7,6 @@ #include -#if defined(XP_WIN) -# define MOZALLOC_EXPORT __declspec(dllexport) -#endif - #include "mozilla/mozalloc_abort.h" namespace std { diff --git a/memory/mozalloc/staticruntime/moz.build b/memory/mozalloc/staticruntime/moz.build new file mode 100644 index 000000000000..56de6a066c0b --- /dev/null +++ b/memory/mozalloc/staticruntime/moz.build @@ -0,0 +1,38 @@ +# -*- 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/. + +NO_VISIBILITY_FLAGS = True + +if CONFIG['MOZ_MSVC_STL_WRAP_RAISE'] or CONFIG['MOZ_MSVC_STL_WRAP_Throw']: + build_msvc_wrappers = 1 +else: + build_msvc_wrappers = 0 + +if CONFIG['WRAP_STL_INCLUDES']: + DEFINES['_HAS_EXCEPTIONS'] = 0 + if build_msvc_wrappers: + SOURCES += [ + '../msvc_raise_wrappers.cpp', + '../msvc_throw_wrapper.cpp', + ] + +UNIFIED_SOURCES += [ + '../mozalloc.cpp', + '../mozalloc_abort.cpp', + '../mozalloc_oom.cpp', +] + +GENERATED_INCLUDES += ['/xpcom'] + +DISABLE_STL_WRAPPING = True + +FAIL_ON_WARNINGS = True + +DEFINES['IMPL_MFBT'] = True + +USE_STATIC_LIBS = True + +Library('mozalloc_staticruntime') diff --git a/mobile/android/installer/package-manifest.in b/mobile/android/installer/package-manifest.in index a87e52c32745..f970eae31fd8 100644 --- a/mobile/android/installer/package-manifest.in +++ b/mobile/android/installer/package-manifest.in @@ -42,7 +42,6 @@ @BINPATH@/@DLL_PREFIX@plds4@DLL_SUFFIX@ @BINPATH@/@DLL_PREFIX@nspr4@DLL_SUFFIX@ #endif -@BINPATH@/@DLL_PREFIX@mozalloc@DLL_SUFFIX@ @BINPATH@/@DLL_PREFIX@omxplugin@DLL_SUFFIX@ @BINPATH@/@DLL_PREFIX@omxplugingb@DLL_SUFFIX@ @BINPATH@/@DLL_PREFIX@omxplugingb235@DLL_SUFFIX@ diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index e90e226c4ce6..cf35f3915e07 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -1717,6 +1717,11 @@ pref("network.stricttransportsecurity.preloadlist", true); pref("converter.html2txt.structs", true); // Output structured phrases (strong, em, code, sub, sup, b, i, u) pref("converter.html2txt.header_strategy", 1); // 0 = no indention; 1 = indention, increased with header level; 2 = numbering and slight indention +// Whether we include ruby annotation in the text despite whether it +// is requested. This was true because we didn't explicitly strip out +// annotations. Set false by default to provide a better behavior, but +// we want to be able to pref-off it if user doesn't like it. +pref("converter.html2txt.always_include_ruby", false); pref("intl.accept_languages", "chrome://global/locale/intl.properties"); pref("intl.menuitems.alwaysappendaccesskeys","chrome://global/locale/intl.properties"); diff --git a/security/manager/ssl/tests/unit/tlsserver/cmd/moz.build b/security/manager/ssl/tests/unit/tlsserver/cmd/moz.build index 6da2e4851f1e..841626c33141 100644 --- a/security/manager/ssl/tests/unit/tlsserver/cmd/moz.build +++ b/security/manager/ssl/tests/unit/tlsserver/cmd/moz.build @@ -18,7 +18,6 @@ LOCAL_INCLUDES += [ ] USE_LIBS += [ - 'mozalloc', 'mozillapkix', 'nspr', 'nss', diff --git a/security/sandbox/mac/Sandbox.mm b/security/sandbox/mac/Sandbox.mm index cdc7022f76cd..79dfcabe725a 100644 --- a/security/sandbox/mac/Sandbox.mm +++ b/security/sandbox/mac/Sandbox.mm @@ -308,7 +308,7 @@ bool StartMacSandbox(MacSandboxInfo aInfo, nsCString &aErrorMessage) } else if (aInfo.type == MacSandboxType_Content) { profile.AppendPrintf(contentSandboxRules, - Preferences::GetInt("security.sandbox.macos.content.level"), + Preferences::GetInt("security.sandbox.content.level"), nsCocoaFeatures::OSXVersionMajor(), nsCocoaFeatures::OSXVersionMinor(), aInfo.appPath.get(), diff --git a/security/sandbox/moz.build b/security/sandbox/moz.build index c755a664f3de..86b917b14e57 100644 --- a/security/sandbox/moz.build +++ b/security/sandbox/moz.build @@ -4,6 +4,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/. +with Files('**'): + BUG_COMPONENT = ('Core', 'Security: Process Sandboxing') + if CONFIG['OS_ARCH'] == 'Linux': DIRS += ['linux'] elif CONFIG['OS_ARCH'] == 'Darwin': diff --git a/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp b/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp index b0030c7f4a26..f961068c88e1 100644 --- a/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp +++ b/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp @@ -69,38 +69,58 @@ SandboxBroker::LaunchApp(const wchar_t *aPath, #if defined(MOZ_CONTENT_SANDBOX) bool -SandboxBroker::SetSecurityLevelForContentProcess(bool aMoreStrict) +SandboxBroker::SetSecurityLevelForContentProcess(int32_t aSandboxLevel) { if (!mPolicy) { return false; } - sandbox::ResultCode result; - bool ret; - if (aMoreStrict) { - result = mPolicy->SetJobLevel(sandbox::JOB_INTERACTIVE, 0); - ret = (sandbox::SBOX_ALL_OK == result); + sandbox::JobLevel jobLevel; + sandbox::TokenLevel accessTokenLevel; + sandbox::IntegrityLevel initialIntegrityLevel; + sandbox::IntegrityLevel delayedIntegrityLevel; - result = mPolicy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS, - sandbox::USER_INTERACTIVE); - ret = ret && (sandbox::SBOX_ALL_OK == result); - - // If the delayed integrity level is lowered then SetUpSandboxEnvironment and - // CleanUpSandboxEnvironment in ContentChild should be changed or removed. - result = mPolicy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW); - ret = ret && (sandbox::SBOX_ALL_OK == result); - - result = mPolicy->SetAlternateDesktop(true); - ret = ret && (sandbox::SBOX_ALL_OK == result); + if (aSandboxLevel > 2) { + jobLevel = sandbox::JOB_LOCKDOWN; + accessTokenLevel = sandbox::USER_LOCKDOWN; + initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW; + delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_UNTRUSTED; + } else if (aSandboxLevel == 2) { + jobLevel = sandbox::JOB_RESTRICTED; + accessTokenLevel = sandbox::USER_LIMITED; + // Ideally we would have an initialIntegrityLevel of LOW here, but this + // immediately causes a problem with the way PBackground is initialized. + initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_MEDIUM; + delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW; + } else if (aSandboxLevel == 1) { + jobLevel = sandbox::JOB_INTERACTIVE; + accessTokenLevel = sandbox::USER_INTERACTIVE; + // INTEGRITY_LEVEL_LAST effectively means don't change from the integrity + // level of the broker process. + initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LAST; + delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW; } else { - result = mPolicy->SetJobLevel(sandbox::JOB_NONE, 0); - ret = (sandbox::SBOX_ALL_OK == result); + jobLevel = sandbox::JOB_NONE; + accessTokenLevel = sandbox::USER_NON_ADMIN; + initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LAST; + delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_MEDIUM; + } - result = mPolicy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS, - sandbox::USER_NON_ADMIN); - ret = ret && (sandbox::SBOX_ALL_OK == result); + sandbox::ResultCode result = mPolicy->SetJobLevel(jobLevel, + 0 /* ui_exceptions */); + bool ret = (sandbox::SBOX_ALL_OK == result); - result = mPolicy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_MEDIUM); + result = mPolicy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS, + accessTokenLevel); + ret = ret && (sandbox::SBOX_ALL_OK == result); + + result = mPolicy->SetIntegrityLevel(initialIntegrityLevel); + ret = ret && (sandbox::SBOX_ALL_OK == result); + result = mPolicy->SetDelayedIntegrityLevel(delayedIntegrityLevel); + ret = ret && (sandbox::SBOX_ALL_OK == result); + + if (aSandboxLevel > 0) { + result = mPolicy->SetAlternateDesktop(true); ret = ret && (sandbox::SBOX_ALL_OK == result); } diff --git a/security/sandbox/win/src/sandboxbroker/sandboxBroker.h b/security/sandbox/win/src/sandboxbroker/sandboxBroker.h index 12cf1d3b762a..79a217ff742a 100644 --- a/security/sandbox/win/src/sandboxbroker/sandboxBroker.h +++ b/security/sandbox/win/src/sandboxbroker/sandboxBroker.h @@ -34,7 +34,7 @@ public: // Security levels for different types of processes #if defined(MOZ_CONTENT_SANDBOX) - bool SetSecurityLevelForContentProcess(bool aMoreStrict); + bool SetSecurityLevelForContentProcess(int32_t aSandboxLevel); #endif bool SetSecurityLevelForPluginProcess(int32_t aSandboxLevel); bool SetSecurityLevelForIPDLUnitTestProcess(); diff --git a/testing/mochitest/mochitest_options.py b/testing/mochitest/mochitest_options.py index a528b1ea7568..9ddb50195c6f 100644 --- a/testing/mochitest/mochitest_options.py +++ b/testing/mochitest/mochitest_options.py @@ -683,7 +683,8 @@ class MochitestOptions(optparse.OptionParser): for f in ['/usr/bin/gst-launch-0.10', '/usr/bin/pactl']: if not os.path.isfile(f): self.error( - 'Missing binary %s required for --use-test-media-devices') + 'Missing binary %s required for ' + '--use-test-media-devices' % f) if options.nested_oop: if not options.e10s: diff --git a/testing/mochitest/runtests.py b/testing/mochitest/runtests.py index d353b71f9528..e48318f951c8 100644 --- a/testing/mochitest/runtests.py +++ b/testing/mochitest/runtests.py @@ -1341,8 +1341,7 @@ class Mochitest(MochitestUtilsMixin): "browser.tabs.remote.autostart=%s" % ('true' if options.e10s else 'false')) if options.strictContentSandbox: - options.extraPrefs.append( - "security.sandbox.windows.content.moreStrict=true") + options.extraPrefs.append("security.sandbox.content.level=1") options.extraPrefs.append( "dom.ipc.tabs.nested.enabled=%s" % ('true' if options.nested_oop else 'false')) diff --git a/testing/mochitest/ssltunnel/moz.build b/testing/mochitest/ssltunnel/moz.build index 77bcdc4c611e..b714d83a445b 100644 --- a/testing/mochitest/ssltunnel/moz.build +++ b/testing/mochitest/ssltunnel/moz.build @@ -11,7 +11,6 @@ SOURCES += [ ] USE_LIBS += [ - 'mozalloc', 'nspr', 'nss', ] diff --git a/toolkit/components/downloads/ApplicationReputation.cpp b/toolkit/components/downloads/ApplicationReputation.cpp index bc4eff4aad39..536beaea17c6 100644 --- a/toolkit/components/downloads/ApplicationReputation.cpp +++ b/toolkit/components/downloads/ApplicationReputation.cpp @@ -296,6 +296,8 @@ PendingDBLookup::LookupSpecInternal(const nsACString& aSpec) LOG(("Checking DB service for principal %s [this = %p]", mSpec.get(), this)); nsCOMPtr dbService = do_GetService(NS_URLCLASSIFIERDBSERVICE_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + nsAutoCString tables; nsAutoCString allowlist; Preferences::GetCString(PREF_DOWNLOAD_ALLOW_TABLE, &allowlist); diff --git a/toolkit/components/telemetry/Telemetry.cpp b/toolkit/components/telemetry/Telemetry.cpp index 2516211d683a..3c3d9e10bc1f 100644 --- a/toolkit/components/telemetry/Telemetry.cpp +++ b/toolkit/components/telemetry/Telemetry.cpp @@ -243,7 +243,7 @@ public: */ struct AnnotationInfo { AnnotationInfo(uint32_t aHangIndex, - UniquePtr aAnnotations) + HangAnnotationsPtr aAnnotations) : mHangIndex(aHangIndex) , mAnnotations(Move(aAnnotations)) {} @@ -259,7 +259,7 @@ public: return *this; } uint32_t mHangIndex; - UniquePtr mAnnotations; + HangAnnotationsPtr mAnnotations; private: // Force move constructor @@ -269,7 +269,7 @@ public: size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; void AddHang(const Telemetry::ProcessedStack& aStack, uint32_t aDuration, int32_t aSystemUptime, int32_t aFirefoxUptime, - UniquePtr aAnnotations); + HangAnnotationsPtr aAnnotations); uint32_t GetDuration(unsigned aIndex) const; int32_t GetSystemUptime(unsigned aIndex) const; int32_t GetFirefoxUptime(unsigned aIndex) const; @@ -298,7 +298,7 @@ HangReports::AddHang(const Telemetry::ProcessedStack& aStack, uint32_t aDuration, int32_t aSystemUptime, int32_t aFirefoxUptime, - UniquePtr aAnnotations) { + HangAnnotationsPtr aAnnotations) { HangInfo info = { aDuration, aSystemUptime, aFirefoxUptime }; mHangInfo.push_back(info); if (aAnnotations) { @@ -658,7 +658,7 @@ public: Telemetry::ProcessedStack &aStack, int32_t aSystemUptime, int32_t aFirefoxUptime, - UniquePtr aAnnotations); + HangAnnotationsPtr aAnnotations); #endif static void RecordThreadHangStats(Telemetry::ThreadHangStats& aStats); static nsresult GetHistogramEnumId(const char *name, Telemetry::ID *id); @@ -2553,9 +2553,9 @@ TelemetryImpl::GetChromeHangs(JSContext *cx, JS::MutableHandle ret) if (!jsAnnotation) { return NS_ERROR_FAILURE; } - nsAutoPtr annotationsEnum; - if (!annotationInfo[iterIndex].mAnnotations->GetEnumerator( - annotationsEnum.StartAssignment())) { + UniquePtr annotationsEnum = + annotationInfo[iterIndex].mAnnotations->GetEnumerator(); + if (!annotationsEnum) { return NS_ERROR_FAILURE; } nsAutoString key; @@ -2839,6 +2839,44 @@ CreateJSHangStack(JSContext* cx, const Telemetry::HangStack& stack) return ret; } +static JSObject* +CreateJSHangAnnotations(JSContext* cx, const HangAnnotationsVector& annotations) +{ + JS::RootedObject annotationsArray(cx, JS_NewArrayObject(cx, 0)); + if (!annotationsArray) { + return nullptr; + } + size_t annotationIndex = 0; + for (const HangAnnotationsPtr *i = annotations.begin(), *e = annotations.end(); + i != e; ++i) { + JS::RootedObject jsAnnotation(cx, JS_NewPlainObject(cx)); + if (!jsAnnotation) { + continue; + } + const HangAnnotationsPtr& curAnnotations = *i; + UniquePtr annotationsEnum = + curAnnotations->GetEnumerator(); + if (!annotationsEnum) { + continue; + } + nsAutoString key; + nsAutoString value; + while (annotationsEnum->Next(key, value)) { + JS::RootedValue jsValue(cx); + jsValue.setString(JS_NewUCStringCopyN(cx, value.get(), value.Length())); + if (!JS_DefineUCProperty(cx, jsAnnotation, key.get(), key.Length(), + jsValue, JSPROP_ENUMERATE)) { + return nullptr; + } + } + if (!JS_SetElement(cx, annotationsArray, annotationIndex, jsAnnotation)) { + continue; + } + ++annotationIndex; + } + return annotationsArray; +} + static JSObject* CreateJSHangHistogram(JSContext* cx, const Telemetry::HangHistogram& hang) { @@ -2849,11 +2887,16 @@ CreateJSHangHistogram(JSContext* cx, const Telemetry::HangHistogram& hang) JS::RootedObject stack(cx, CreateJSHangStack(cx, hang.GetStack())); JS::RootedObject time(cx, CreateJSTimeHistogram(cx, hang)); + auto& hangAnnotations = hang.GetAnnotations(); + JS::RootedObject annotations(cx, CreateJSHangAnnotations(cx, hangAnnotations)); if (!stack || !time || + !annotations || !JS_DefineProperty(cx, ret, "stack", stack, JSPROP_ENUMERATE) || - !JS_DefineProperty(cx, ret, "histogram", time, JSPROP_ENUMERATE)) { + !JS_DefineProperty(cx, ret, "histogram", time, JSPROP_ENUMERATE) || + (!hangAnnotations.empty() && // <-- Only define annotations when nonempty + !JS_DefineProperty(cx, ret, "annotations", annotations, JSPROP_ENUMERATE))) { return nullptr; } @@ -2899,6 +2942,7 @@ CreateJSThreadHangStats(JSContext* cx, const Telemetry::ThreadHangStats& thread) if (!JS_DefineProperty(cx, ret, "hangs", hangs, JSPROP_ENUMERATE)) { return nullptr; } + return ret; } @@ -3333,12 +3377,12 @@ TelemetryImpl::RecordChromeHang(uint32_t aDuration, Telemetry::ProcessedStack &aStack, int32_t aSystemUptime, int32_t aFirefoxUptime, - UniquePtr aAnnotations) + HangAnnotationsPtr aAnnotations) { if (!sTelemetry || !sTelemetry->mCanRecord) return; - UniquePtr annotations; + HangAnnotationsPtr annotations; // We only pass aAnnotations if it is not empty. if (aAnnotations && !aAnnotations->IsEmpty()) { annotations = Move(aAnnotations); @@ -3607,7 +3651,7 @@ void RecordChromeHang(uint32_t duration, ProcessedStack &aStack, int32_t aSystemUptime, int32_t aFirefoxUptime, - UniquePtr aAnnotations) + HangAnnotationsPtr aAnnotations) { TelemetryImpl::RecordChromeHang(duration, aStack, aSystemUptime, aFirefoxUptime, diff --git a/toolkit/components/telemetry/ThreadHangStats.h b/toolkit/components/telemetry/ThreadHangStats.h index 802d25acba9a..859e52eafc52 100644 --- a/toolkit/components/telemetry/ThreadHangStats.h +++ b/toolkit/components/telemetry/ThreadHangStats.h @@ -8,6 +8,7 @@ #include "mozilla/Array.h" #include "mozilla/Assertions.h" +#include "mozilla/HangAnnotations.h" #include "mozilla/Move.h" #include "mozilla/Mutex.h" #include "mozilla/PodOperations.h" @@ -119,6 +120,8 @@ private: HangStack mNativeStack; // Use a hash to speed comparisons const uint32_t mHash; + // Annotations attributed to this stack + HangMonitor::HangAnnotationsVector mAnnotations; public: explicit HangHistogram(HangStack&& aStack) @@ -131,6 +134,7 @@ public: , mStack(mozilla::Move(aOther.mStack)) , mNativeStack(mozilla::Move(aOther.mNativeStack)) , mHash(mozilla::Move(aOther.mHash)) + , mAnnotations(mozilla::Move(aOther.mAnnotations)) { } bool operator==(const HangHistogram& aOther) const; @@ -147,12 +151,23 @@ public: const HangStack& GetNativeStack() const { return mNativeStack; } + const HangMonitor::HangAnnotationsVector& GetAnnotations() const { + return mAnnotations; + } + void Add(PRIntervalTime aTime, HangMonitor::HangAnnotationsPtr aAnnotations) { + TimeHistogram::Add(aTime); + if (aAnnotations) { + mAnnotations.append(Move(aAnnotations)); + } + } }; /* Thread hang stats consist of - thread name - time histogram of all task run times - - hang histograms of individual hangs. */ + - hang histograms of individual hangs + - annotations for each hang +*/ class ThreadHangStats { private: diff --git a/toolkit/library/moz.build b/toolkit/library/moz.build index 40f9a39ec0f3..7512a29e464a 100644 --- a/toolkit/library/moz.build +++ b/toolkit/library/moz.build @@ -113,7 +113,6 @@ if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT': USE_LIBS += [ 'gkmedias', - 'mozalloc', 'nspr', 'nss', 'sqlite', diff --git a/toolkit/mozapps/installer/upload-files.mk b/toolkit/mozapps/installer/upload-files.mk index b546717b9f64..346e056c8e42 100644 --- a/toolkit/mozapps/installer/upload-files.mk +++ b/toolkit/mozapps/installer/upload-files.mk @@ -270,7 +270,6 @@ include $(MOZILLA_DIR)/config/android-common.mk DIST_FILES = # Place the files in the order they are going to be opened by the linker -DIST_FILES += libmozalloc.so ifndef MOZ_FOLD_LIBS DIST_FILES += \ libnspr4.so \ diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index 83f5cbfbf9b0..9302e6721548 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -458,6 +458,8 @@ CheckArg(const char* aArg, bool aCheckOSInt = false, const char **aParam = nullp if (strimatch(aArg, arg)) { if (aRemArg) RemoveArg(curarg); + else + ++curarg; if (!aParam) { ar = ARG_FOUND; break; @@ -1632,10 +1634,17 @@ RemoteCommandLine(const char* aDesktopStartupID) nsresult rv; ArgResult ar; + const char *profile = 0; nsAutoCString program(gAppData->remotingName); ToLowerCase(program); const char *username = getenv("LOGNAME"); + ar = CheckArg("p", false, &profile, false); + if (ar == ARG_BAD) { + PR_fprintf(PR_STDERR, "Error: argument -p requires a profile name\n"); + return REMOTE_ARG_BAD; + } + const char *temp = nullptr; ar = CheckArg("a", true, &temp); if (ar == ARG_BAD) { @@ -1658,7 +1667,7 @@ RemoteCommandLine(const char* aDesktopStartupID) nsXPIDLCString response; bool success = false; - rv = client.SendCommandLine(program.get(), username, nullptr, + rv = client.SendCommandLine(program.get(), username, profile, gArgc, gArgv, aDesktopStartupID, getter_Copies(response), &success); // did the command fail? diff --git a/xpcom/base/nscore.h b/xpcom/base/nscore.h index bf662f919035..060af1d46e80 100644 --- a/xpcom/base/nscore.h +++ b/xpcom/base/nscore.h @@ -289,10 +289,6 @@ typedef MozRefCountType nsrefcnt; #define XPCOM_GLUE_AVOID_NSPR #endif -#if defined(HAVE_THREAD_TLS_KEYWORD) -#define NS_TLS __thread -#endif - /* * SEH exception macros. */ diff --git a/xpcom/glue/MainThreadUtils.h b/xpcom/glue/MainThreadUtils.h index b6b05ec50fa8..e03f39f69dd5 100644 --- a/xpcom/glue/MainThreadUtils.h +++ b/xpcom/glue/MainThreadUtils.h @@ -8,7 +8,6 @@ #define MainThreadUtils_h_ #include "nscore.h" -#include "mozilla/threads/nsThreadIDs.h" class nsIThread; diff --git a/xpcom/glue/moz.build b/xpcom/glue/moz.build index 27c6d1473b2d..a1709df973e7 100644 --- a/xpcom/glue/moz.build +++ b/xpcom/glue/moz.build @@ -4,7 +4,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/. -DIRS += ['standalone', 'nomozalloc'] +DIRS += ['standalone'] # On win we build two glue libs - glue linked to crt dlls here and in staticruntime we build # a statically linked glue lib. @@ -80,10 +80,6 @@ EXPORTS.mozilla += [ 'ReentrantMonitor.h', ] -EXPORTS.mozilla.threads += [ - 'nsThreadIDs.h', -] - include('objs.mozbuild') UNIFIED_SOURCES += xpcom_gluens_src_cppsrcs diff --git a/xpcom/glue/nomozalloc/Makefile.in b/xpcom/glue/nomozalloc/Makefile.in deleted file mode 100644 index 53281f1d03de..000000000000 --- a/xpcom/glue/nomozalloc/Makefile.in +++ /dev/null @@ -1,8 +0,0 @@ -# vim:set ts=8 sw=8 sts=8 noet: -# 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/. - -DIST_INSTALL = 1 -# Force to build a static library only -NO_EXPAND_LIBS = 1 diff --git a/xpcom/glue/nomozalloc/moz.build b/xpcom/glue/nomozalloc/moz.build deleted file mode 100644 index df53bca9bb71..000000000000 --- a/xpcom/glue/nomozalloc/moz.build +++ /dev/null @@ -1,49 +0,0 @@ -# -*- 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/. - -include('../objs.mozbuild') - -UNIFIED_SOURCES += xpcom_gluens_src_cppsrcs -UNIFIED_SOURCES += xpcom_glue_src_cppsrcs - -UNIFIED_SOURCES += [ - '../GenericModule.cpp', - '../nsStringAPI.cpp', -] - -Library('xpcomglue_s_nomozalloc') - -SDK_LIBRARY = True - -# we don't want the shared lib, but we want to force the creation of a static lib. -FORCE_STATIC_LIB = True - -if CONFIG['_MSC_VER']: - DEFINES['_USE_ANSI_CPP'] = True - # Don't include directives about which CRT to use - CFLAGS += ['-Zl'] - CXXFLAGS += ['-Zl'] - -DEFINES['MOZ_NO_MOZALLOC'] = True - -LOCAL_INCLUDES += [ - '../../build', -] - -# Pretend we're statically linking the CRT, even though we might not be: this -# avoids "msvcrp" and assembly dependencies from creeping into the directives -# for this library on Windows. -USE_STATIC_LIBS = True - -# Don't use STL wrappers here (i.e. wrapped ); they require mozalloc -DISABLE_STL_WRAPPING = True - -FAIL_ON_WARNINGS = True - -# Include fallible for third party code using the xpcom glue -USE_LIBS += [ - 'fallible', -] diff --git a/xpcom/glue/nsThreadIDs.h b/xpcom/glue/nsThreadIDs.h deleted file mode 100644 index 13344e28b189..000000000000 --- a/xpcom/glue/nsThreadIDs.h +++ /dev/null @@ -1,22 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef _mozilla_threads_nsThreadIDs_h_ -#define _mozilla_threads_nsThreadIDs_h_ - -namespace mozilla { -namespace threads { - -enum ID -{ - Generic = 0, - Main = 1, -}; - -} /* namespace threads */ -} /* namespace mozilla */ - -#endif /* _mozilla_threads_nsThreadIDs_h_ */ diff --git a/xpcom/threads/BackgroundHangMonitor.cpp b/xpcom/threads/BackgroundHangMonitor.cpp index d4fef4b7387c..24612c7bed44 100644 --- a/xpcom/threads/BackgroundHangMonitor.cpp +++ b/xpcom/threads/BackgroundHangMonitor.cpp @@ -164,6 +164,10 @@ public: Telemetry::HangStack mHangStack; // Statistics for telemetry Telemetry::ThreadHangStats mStats; + // Annotations for the current hang + UniquePtr mAnnotations; + // Annotators registered for this thread + HangMonitor::Observer::Annotators mAnnotators; BackgroundHangThread(const char* aName, uint32_t aTimeoutMs, @@ -299,6 +303,8 @@ BackgroundHangManager::RunMonitorThread() currentThread->mStackHelper.GetStack(currentThread->mHangStack); currentThread->mHangStart = interval; currentThread->mHanging = true; + currentThread->mAnnotations = + currentThread->mAnnotators.GatherAnnotations(); } } else { if (MOZ_LIKELY(interval != currentThread->mHangStart)) { @@ -397,12 +403,12 @@ BackgroundHangThread::ReportHang(PRIntervalTime aHangTime) oldHistogram != mStats.mHangs.end(); oldHistogram++) { if (newHistogram == *oldHistogram) { // New histogram matches old one - oldHistogram->Add(aHangTime); + oldHistogram->Add(aHangTime, Move(mAnnotations)); return *oldHistogram; } } // Add new histogram - newHistogram.Add(aHangTime); + newHistogram.Add(aHangTime, Move(mAnnotations)); mStats.mHangs.append(Move(newHistogram)); return mStats.mHangs.back(); } @@ -642,6 +648,33 @@ BackgroundHangMonitor::Allow() #endif } +bool +BackgroundHangMonitor::RegisterAnnotator(HangMonitor::Annotator& aAnnotator) +{ +#ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR + BackgroundHangThread* thisThread = BackgroundHangThread::FindThread(); + if (!thisThread) { + return false; + } + return thisThread->mAnnotators.Register(aAnnotator); +#else + return false; +#endif +} + +bool +BackgroundHangMonitor::UnregisterAnnotator(HangMonitor::Annotator& aAnnotator) +{ +#ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR + BackgroundHangThread* thisThread = BackgroundHangThread::FindThread(); + if (!thisThread) { + return false; + } + return thisThread->mAnnotators.Unregister(aAnnotator); +#else + return false; +#endif +} /* Because we are iterating through the BackgroundHangThread linked list, we need to take a lock. Using MonitorAutoLock as a base class makes diff --git a/xpcom/threads/BackgroundHangMonitor.h b/xpcom/threads/BackgroundHangMonitor.h index 333ae086b704..774b0d52581e 100644 --- a/xpcom/threads/BackgroundHangMonitor.h +++ b/xpcom/threads/BackgroundHangMonitor.h @@ -7,8 +7,9 @@ #ifndef mozilla_BackgroundHangMonitor_h #define mozilla_BackgroundHangMonitor_h -#include "mozilla/RefPtr.h" +#include "mozilla/HangAnnotations.h" #include "mozilla/Monitor.h" +#include "mozilla/RefPtr.h" #include "nsString.h" @@ -233,6 +234,21 @@ public: * \see Prohibit() */ static void Allow(); + + /** + * Register an annotator with BHR for the current thread. + * @param aAnnotator annotator to register + * @return true if the annotator was registered, otherwise false. + */ + static bool RegisterAnnotator(HangMonitor::Annotator& aAnnotator); + + /** + * Unregister an annotator that was previously registered via + * RegisterAnnotator. + * @param aAnnotator annotator to unregister + * @return true if there are still remaining annotators registered + */ + static bool UnregisterAnnotator(HangMonitor::Annotator& aAnnotator); }; } // namespace mozilla diff --git a/xpcom/threads/HangAnnotations.cpp b/xpcom/threads/HangAnnotations.cpp new file mode 100644 index 000000000000..7797727d2d03 --- /dev/null +++ b/xpcom/threads/HangAnnotations.cpp @@ -0,0 +1,262 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/HangAnnotations.h" + +#include + +#include "MainThreadUtils.h" +#include "mozilla/DebugOnly.h" +#include "nsXULAppAPI.h" + +namespace mozilla { +namespace HangMonitor { + +// Chrome hang annotators. This can go away once BHR has completely replaced +// ChromeHangs. +static StaticAutoPtr gChromehangAnnotators; + +class BrowserHangAnnotations : public HangAnnotations +{ +public: + BrowserHangAnnotations(); + ~BrowserHangAnnotations(); + + void AddAnnotation(const nsAString& aName, const int32_t aData) MOZ_OVERRIDE; + void AddAnnotation(const nsAString& aName, const double aData) MOZ_OVERRIDE; + void AddAnnotation(const nsAString& aName, const nsAString& aData) MOZ_OVERRIDE; + void AddAnnotation(const nsAString& aName, const nsACString& aData) MOZ_OVERRIDE; + void AddAnnotation(const nsAString& aName, const bool aData) MOZ_OVERRIDE; + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE; + bool IsEmpty() const MOZ_OVERRIDE; + UniquePtr GetEnumerator() MOZ_OVERRIDE; + + typedef std::pair AnnotationType; + typedef std::vector VectorType; + typedef VectorType::const_iterator IteratorType; + +private: + VectorType mAnnotations; +}; + +BrowserHangAnnotations::BrowserHangAnnotations() +{ + MOZ_COUNT_CTOR(BrowserHangAnnotations); +} + +BrowserHangAnnotations::~BrowserHangAnnotations() +{ + MOZ_COUNT_DTOR(BrowserHangAnnotations); +} + +void +BrowserHangAnnotations::AddAnnotation(const nsAString& aName, const int32_t aData) +{ + nsString dataString; + dataString.AppendInt(aData); + AnnotationType annotation = std::make_pair(nsString(aName), dataString); + mAnnotations.push_back(annotation); +} + +void +BrowserHangAnnotations::AddAnnotation(const nsAString& aName, const double aData) +{ + nsString dataString; + dataString.AppendFloat(aData); + AnnotationType annotation = std::make_pair(nsString(aName), dataString); + mAnnotations.push_back(annotation); +} + +void +BrowserHangAnnotations::AddAnnotation(const nsAString& aName, const nsAString& aData) +{ + AnnotationType annotation = std::make_pair(nsString(aName), nsString(aData)); + mAnnotations.push_back(annotation); +} + +void +BrowserHangAnnotations::AddAnnotation(const nsAString& aName, const nsACString& aData) +{ + nsString dataString; + AppendUTF8toUTF16(aData, dataString); + AnnotationType annotation = std::make_pair(nsString(aName), dataString); + mAnnotations.push_back(annotation); +} + +void +BrowserHangAnnotations::AddAnnotation(const nsAString& aName, const bool aData) +{ + nsString dataString; + dataString += aData ? NS_LITERAL_STRING("true") : NS_LITERAL_STRING("false"); + AnnotationType annotation = std::make_pair(nsString(aName), dataString); + mAnnotations.push_back(annotation); +} + +/** + * This class itself does not use synchronization but it (and its parent object) + * should be protected by mutual exclusion in some way. In Telemetry the chrome + * hang data is protected via TelemetryImpl::mHangReportsMutex. + */ +class ChromeHangAnnotationEnumerator : public HangAnnotations::Enumerator +{ +public: + explicit ChromeHangAnnotationEnumerator(const BrowserHangAnnotations::VectorType& aAnnotations); + ~ChromeHangAnnotationEnumerator(); + + virtual bool Next(nsAString& aOutName, nsAString& aOutValue); + +private: + BrowserHangAnnotations::IteratorType mIterator; + BrowserHangAnnotations::IteratorType mEnd; +}; + +ChromeHangAnnotationEnumerator::ChromeHangAnnotationEnumerator( + const BrowserHangAnnotations::VectorType& aAnnotations) + : mIterator(aAnnotations.begin()) + , mEnd(aAnnotations.end()) +{ + MOZ_COUNT_CTOR(ChromeHangAnnotationEnumerator); +} + +ChromeHangAnnotationEnumerator::~ChromeHangAnnotationEnumerator() +{ + MOZ_COUNT_DTOR(ChromeHangAnnotationEnumerator); +} + +bool +ChromeHangAnnotationEnumerator::Next(nsAString& aOutName, nsAString& aOutValue) +{ + aOutName.Truncate(); + aOutValue.Truncate(); + if (mIterator == mEnd) { + return false; + } + aOutName = mIterator->first; + aOutValue = mIterator->second; + ++mIterator; + return true; +} + +bool +BrowserHangAnnotations::IsEmpty() const +{ + return mAnnotations.empty(); +} + +size_t +BrowserHangAnnotations::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const +{ + size_t result = sizeof(mAnnotations) + + mAnnotations.capacity() * sizeof(AnnotationType); + for (IteratorType i = mAnnotations.begin(), e = mAnnotations.end(); i != e; + ++i) { + result += i->first.SizeOfExcludingThisIfUnshared(aMallocSizeOf); + result += i->second.SizeOfExcludingThisIfUnshared(aMallocSizeOf); + } + + return result; +} + +UniquePtr +BrowserHangAnnotations::GetEnumerator() +{ + if (mAnnotations.empty()) { + return nullptr; + } + return MakeUnique(mAnnotations); +} + +namespace Observer { + +Annotators::Annotators() + : mMutex("HangMonitor::Annotators::mMutex") +{ + MOZ_COUNT_CTOR(Annotators); +} + +Annotators::~Annotators() +{ + MOZ_ASSERT(mAnnotators.empty()); + MOZ_COUNT_DTOR(Annotators); +} + +bool +Annotators::Register(Annotator& aAnnotator) +{ + MutexAutoLock lock(mMutex); + auto result = mAnnotators.insert(&aAnnotator); + return result.second; +} + +bool +Annotators::Unregister(Annotator& aAnnotator) +{ + MutexAutoLock lock(mMutex); + DebugOnly::size_type> numErased; + numErased = mAnnotators.erase(&aAnnotator); + MOZ_ASSERT(numErased == 1); + return mAnnotators.empty(); +} + +UniquePtr +Annotators::GatherAnnotations() +{ + auto annotations = MakeUnique(); + { // Scope for lock + MutexAutoLock lock(mMutex); + for (std::set::iterator i = mAnnotators.begin(), + e = mAnnotators.end(); + i != e; ++i) { + (*i)->AnnotateHang(*annotations); + } + } + if (annotations->IsEmpty()) { + return nullptr; + } + return Move(annotations); +} + +} // namespace Observer + +void +RegisterAnnotator(Annotator& aAnnotator) +{ + BackgroundHangMonitor::RegisterAnnotator(aAnnotator); + // We still register annotators for ChromeHangs + if (NS_IsMainThread() && + GeckoProcessType_Default == XRE_GetProcessType()) { + if (!gChromehangAnnotators) { + gChromehangAnnotators = new Observer::Annotators(); + } + gChromehangAnnotators->Register(aAnnotator); + } +} + +void +UnregisterAnnotator(Annotator& aAnnotator) +{ + BackgroundHangMonitor::UnregisterAnnotator(aAnnotator); + // We still register annotators for ChromeHangs + if (NS_IsMainThread() && + GeckoProcessType_Default == XRE_GetProcessType()) { + if (gChromehangAnnotators->Unregister(aAnnotator)) { + gChromehangAnnotators = nullptr; + } + } +} + +UniquePtr +ChromeHangAnnotatorCallout() +{ + if (!gChromehangAnnotators) { + return nullptr; + } + return gChromehangAnnotators->GatherAnnotations(); +} + +} // namespace HangMonitor +} // namespace mozilla diff --git a/xpcom/threads/HangAnnotations.h b/xpcom/threads/HangAnnotations.h new file mode 100644 index 000000000000..6dddbf4bb466 --- /dev/null +++ b/xpcom/threads/HangAnnotations.h @@ -0,0 +1,104 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_HangAnnotations_h +#define mozilla_HangAnnotations_h + +#include + +#include "mozilla/MemoryReporting.h" +#include "mozilla/Mutex.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/Vector.h" +#include "nsString.h" + +namespace mozilla { +namespace HangMonitor { + +/** + * This class declares an abstraction for a data type that encapsulates all + * of the annotations being reported by a registered hang Annotator. + */ +class HangAnnotations +{ +public: + virtual ~HangAnnotations() {} + + virtual void AddAnnotation(const nsAString& aName, const int32_t aData) = 0; + virtual void AddAnnotation(const nsAString& aName, const double aData) = 0; + virtual void AddAnnotation(const nsAString& aName, const nsAString& aData) = 0; + virtual void AddAnnotation(const nsAString& aName, const nsACString& aData) = 0; + virtual void AddAnnotation(const nsAString& aName, const bool aData) = 0; + + class Enumerator + { + public: + virtual ~Enumerator() {} + virtual bool Next(nsAString& aOutName, nsAString& aOutValue) = 0; + }; + + virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const = 0; + virtual bool IsEmpty() const = 0; + virtual UniquePtr GetEnumerator() = 0; +}; + +typedef UniquePtr HangAnnotationsPtr; +typedef Vector HangAnnotationsVector; + +class Annotator +{ +public: + /** + * NB: This function is always called by the HangMonitor thread. + * Plan accordingly. + */ + virtual void AnnotateHang(HangAnnotations& aAnnotations) = 0; +}; + +/** + * Registers an Annotator to be called when a hang is detected. + * @param aAnnotator Reference to an object that implements the + * HangMonitor::Annotator interface. + */ +void RegisterAnnotator(Annotator& aAnnotator); + +/** + * Registers an Annotator that was previously registered via RegisterAnnotator. + * @param aAnnotator Reference to an object that implements the + * HangMonitor::Annotator interface. + */ +void UnregisterAnnotator(Annotator& aAnnotator); + +/** + * Gathers annotations. This function should be called by ChromeHangs. + * @return UniquePtr to HangAnnotations object or nullptr if none. + */ +HangAnnotationsPtr ChromeHangAnnotatorCallout(); + +namespace Observer { + +class Annotators +{ +public: + Annotators(); + ~Annotators(); + + bool Register(Annotator& aAnnotator); + bool Unregister(Annotator& aAnnotator); + + HangAnnotationsPtr GatherAnnotations(); + +private: + Mutex mMutex; + std::set mAnnotators; +}; + +} // namespace Observer + +} // namespace HangMonitor +} // namespace mozilla + +#endif // mozilla_HangAnnotations_h diff --git a/xpcom/threads/HangMonitor.cpp b/xpcom/threads/HangMonitor.cpp index a2e3d7b4f81d..81b0f384faf6 100644 --- a/xpcom/threads/HangMonitor.cpp +++ b/xpcom/threads/HangMonitor.cpp @@ -6,8 +6,6 @@ #include "mozilla/HangMonitor.h" -#include - #include "mozilla/Atomics.h" #include "mozilla/BackgroundHangMonitor.h" #include "mozilla/Monitor.h" @@ -74,9 +72,6 @@ static const int32_t DEFAULT_CHROME_HANG_INTERVAL = 5; // Maximum number of PCs to gather from the stack static const int32_t MAX_CALL_STACK_PCS = 400; - -// Chrome hang annotators -static StaticAutoPtr> gAnnotators; #endif // PrefChangedFunc @@ -122,161 +117,6 @@ Crash() } #ifdef REPORT_CHROME_HANGS -class ChromeHangAnnotations : public HangAnnotations -{ -public: - ChromeHangAnnotations(); - ~ChromeHangAnnotations(); - - void AddAnnotation(const nsAString& aName, const int32_t aData) MOZ_OVERRIDE; - void AddAnnotation(const nsAString& aName, const double aData) MOZ_OVERRIDE; - void AddAnnotation(const nsAString& aName, const nsAString& aData) MOZ_OVERRIDE; - void AddAnnotation(const nsAString& aName, const nsACString& aData) MOZ_OVERRIDE; - void AddAnnotation(const nsAString& aName, const bool aData) MOZ_OVERRIDE; - - size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE; - bool IsEmpty() const MOZ_OVERRIDE; - bool GetEnumerator(Enumerator** aOutEnum) MOZ_OVERRIDE; - - typedef std::pair AnnotationType; - typedef std::vector VectorType; - typedef VectorType::const_iterator IteratorType; - -private: - VectorType mAnnotations; -}; - -ChromeHangAnnotations::ChromeHangAnnotations() -{ - MOZ_COUNT_CTOR(ChromeHangAnnotations); -} - -ChromeHangAnnotations::~ChromeHangAnnotations() -{ - MOZ_COUNT_DTOR(ChromeHangAnnotations); -} - -void -ChromeHangAnnotations::AddAnnotation(const nsAString& aName, const int32_t aData) -{ - nsString dataString; - dataString.AppendInt(aData); - AnnotationType annotation = std::make_pair(nsString(aName), dataString); - mAnnotations.push_back(annotation); -} - -void -ChromeHangAnnotations::AddAnnotation(const nsAString& aName, const double aData) -{ - nsString dataString; - dataString.AppendFloat(aData); - AnnotationType annotation = std::make_pair(nsString(aName), dataString); - mAnnotations.push_back(annotation); -} - -void -ChromeHangAnnotations::AddAnnotation(const nsAString& aName, const nsAString& aData) -{ - AnnotationType annotation = std::make_pair(nsString(aName), nsString(aData)); - mAnnotations.push_back(annotation); -} - -void -ChromeHangAnnotations::AddAnnotation(const nsAString& aName, const nsACString& aData) -{ - nsString dataString; - AppendUTF8toUTF16(aData, dataString); - AnnotationType annotation = std::make_pair(nsString(aName), dataString); - mAnnotations.push_back(annotation); -} - -void -ChromeHangAnnotations::AddAnnotation(const nsAString& aName, const bool aData) -{ - nsString dataString; - dataString += aData ? NS_LITERAL_STRING("true") : NS_LITERAL_STRING("false"); - AnnotationType annotation = std::make_pair(nsString(aName), dataString); - mAnnotations.push_back(annotation); -} - -/** - * This class itself does not use synchronization but it (and its parent object) - * should be protected by mutual exclusion in some way. In Telemetry the chrome - * hang data is protected via TelemetryImpl::mHangReportsMutex. - */ -class ChromeHangAnnotationEnumerator : public HangAnnotations::Enumerator -{ -public: - ChromeHangAnnotationEnumerator(const ChromeHangAnnotations::VectorType& aAnnotations); - ~ChromeHangAnnotationEnumerator(); - - virtual bool Next(nsAString& aOutName, nsAString& aOutValue); - -private: - ChromeHangAnnotations::IteratorType mIterator; - ChromeHangAnnotations::IteratorType mEnd; -}; - -ChromeHangAnnotationEnumerator::ChromeHangAnnotationEnumerator( - const ChromeHangAnnotations::VectorType& aAnnotations) - : mIterator(aAnnotations.begin()) - , mEnd(aAnnotations.end()) -{ - MOZ_COUNT_CTOR(ChromeHangAnnotationEnumerator); -} - -ChromeHangAnnotationEnumerator::~ChromeHangAnnotationEnumerator() -{ - MOZ_COUNT_DTOR(ChromeHangAnnotationEnumerator); -} - -bool -ChromeHangAnnotationEnumerator::Next(nsAString& aOutName, nsAString& aOutValue) -{ - aOutName.Truncate(); - aOutValue.Truncate(); - if (mIterator == mEnd) { - return false; - } - aOutName = mIterator->first; - aOutValue = mIterator->second; - ++mIterator; - return true; -} - -bool -ChromeHangAnnotations::IsEmpty() const -{ - return mAnnotations.empty(); -} - -size_t -ChromeHangAnnotations::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const -{ - size_t result = sizeof(mAnnotations) + - mAnnotations.capacity() * sizeof(AnnotationType); - for (IteratorType i = mAnnotations.begin(), e = mAnnotations.end(); i != e; - ++i) { - result += i->first.SizeOfExcludingThisIfUnshared(aMallocSizeOf); - result += i->second.SizeOfExcludingThisIfUnshared(aMallocSizeOf); - } - - return result; -} - -bool -ChromeHangAnnotations::GetEnumerator(HangAnnotations::Enumerator** aOutEnum) -{ - if (!aOutEnum) { - return false; - } - *aOutEnum = nullptr; - if (mAnnotations.empty()) { - return false; - } - *aOutEnum = new ChromeHangAnnotationEnumerator(mAnnotations); - return true; -} static void ChromeStackWalker(uint32_t aFrameNumber, void* aPC, void* aSP, void* aClosure) @@ -329,21 +169,6 @@ GetChromeHangReport(Telemetry::ProcessedStack& aStack, } } -static void -ChromeHangAnnotatorCallout(ChromeHangAnnotations& aAnnotations) -{ - gMonitor->AssertCurrentThreadOwns(); - MOZ_ASSERT(gAnnotators); - if (!gAnnotators) { - return; - } - for (std::set::iterator i = gAnnotators->begin(), - e = gAnnotators->end(); - i != e; ++i) { - (*i)->AnnotateHang(aAnnotations); - } -} - #endif void @@ -363,7 +188,7 @@ ThreadMain(void*) Telemetry::ProcessedStack stack; int32_t systemUptime = -1; int32_t firefoxUptime = -1; - auto annotations = MakeUnique(); + UniquePtr annotations; #endif while (true) { @@ -391,7 +216,7 @@ ThreadMain(void*) // the minimum hang duration has been reached (not when the hang ends) if (waitCount == 2) { GetChromeHangReport(stack, systemUptime, firefoxUptime); - ChromeHangAnnotatorCallout(*annotations); + annotations = ChromeHangAnnotatorCallout(); } #else // This is the crash-on-hang feature. @@ -412,7 +237,6 @@ ThreadMain(void*) Telemetry::RecordChromeHang(hangDuration, stack, systemUptime, firefoxUptime, Move(annotations)); stack.Clear(); - annotations = MakeUnique(); } #endif lastTimestamp = timestamp; @@ -452,7 +276,6 @@ Startup() if (!winMainThreadHandle) { return; } - gAnnotators = new std::set(); #endif // Don't actually start measuring hangs until we hit the main event loop. @@ -491,11 +314,6 @@ Shutdown() delete gMonitor; gMonitor = nullptr; - -#ifdef REPORT_CHROME_HANGS - // gAnnotators is a StaticAutoPtr, so we just need to null it out. - gAnnotators = nullptr; -#endif } static bool @@ -584,31 +402,5 @@ Suspend() } } -void -RegisterAnnotator(Annotator& aAnnotator) -{ -#ifdef REPORT_CHROME_HANGS - if (GeckoProcessType_Default != XRE_GetProcessType()) { - return; - } - MonitorAutoLock lock(*gMonitor); - MOZ_ASSERT(gAnnotators); - gAnnotators->insert(&aAnnotator); -#endif -} - -void -UnregisterAnnotator(Annotator& aAnnotator) -{ -#ifdef REPORT_CHROME_HANGS - if (GeckoProcessType_Default != XRE_GetProcessType()) { - return; - } - MonitorAutoLock lock(*gMonitor); - MOZ_ASSERT(gAnnotators); - gAnnotators->erase(&aAnnotator); -#endif -} - } // namespace HangMonitor } // namespace mozilla diff --git a/xpcom/threads/HangMonitor.h b/xpcom/threads/HangMonitor.h index b8b2291e1d78..fd0e6ff8390c 100644 --- a/xpcom/threads/HangMonitor.h +++ b/xpcom/threads/HangMonitor.h @@ -7,9 +7,6 @@ #ifndef mozilla_HangMonitor_h #define mozilla_HangMonitor_h -#include "mozilla/MemoryReporting.h" -#include "nsString.h" - namespace mozilla { namespace HangMonitor { @@ -41,57 +38,6 @@ void Startup(); */ void Shutdown(); -/** - * This class declares an abstraction for a data type that encapsulates all - * of the annotations being reported by a registered hang Annotator. - */ -class HangAnnotations -{ -public: - virtual ~HangAnnotations() {} - - virtual void AddAnnotation(const nsAString& aName, const int32_t aData) = 0; - virtual void AddAnnotation(const nsAString& aName, const double aData) = 0; - virtual void AddAnnotation(const nsAString& aName, const nsAString& aData) = 0; - virtual void AddAnnotation(const nsAString& aName, const nsACString& aData) = 0; - virtual void AddAnnotation(const nsAString& aName, const bool aData) = 0; - - class Enumerator - { - public: - virtual ~Enumerator() {} - virtual bool Next(nsAString& aOutName, nsAString& aOutValue) = 0; - }; - - virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const = 0; - virtual bool IsEmpty() const = 0; - virtual bool GetEnumerator(Enumerator **aOutEnum) = 0; -}; - -class Annotator -{ -public: - /** - * NB: This function is always called by the HangMonitor thread. - * Plan accordingly. - */ - virtual void AnnotateHang(HangAnnotations& aAnnotations) = 0; -}; - -/** - * Registers an Annotator to be called when a hang is detected. - * @param aAnnotator Reference to an object that implements the - * HangMonitor::Annotator interface. - */ -void RegisterAnnotator(Annotator& aAnnotator); - -/** - * Registers an Annotator that was previously registered via RegisterAnnotator. - * @param aAnnotator Reference to an object that implements the - * HangMonitor::Annotator interface. - */ -void UnregisterAnnotator(Annotator& aAnnotator); - /** * Notify the hang monitor of activity which will reset its internal timer. * diff --git a/xpcom/threads/moz.build b/xpcom/threads/moz.build index d9c8b0ec132e..a4e906d2a671 100644 --- a/xpcom/threads/moz.build +++ b/xpcom/threads/moz.build @@ -29,6 +29,7 @@ EXPORTS += [ EXPORTS.mozilla += [ 'BackgroundHangMonitor.h', + 'HangAnnotations.h', 'HangMonitor.h', 'LazyIdleThread.h', 'SyncRunnable.h', @@ -36,6 +37,7 @@ EXPORTS.mozilla += [ UNIFIED_SOURCES += [ 'BackgroundHangMonitor.cpp', + 'HangAnnotations.cpp', 'HangMonitor.cpp', 'LazyIdleThread.cpp', 'nsEnvironment.cpp', diff --git a/xpcom/threads/nsThreadManager.cpp b/xpcom/threads/nsThreadManager.cpp index 8de08cfeab06..45d6bb51be01 100644 --- a/xpcom/threads/nsThreadManager.cpp +++ b/xpcom/threads/nsThreadManager.cpp @@ -19,13 +19,6 @@ using namespace mozilla; -#ifdef XP_WIN -#include -DWORD gTLSThreadIDIndex = TlsAlloc(); -#elif defined(NS_TLS) -NS_TLS mozilla::threads::ID gTLSThreadID = mozilla::threads::Generic; -#endif - static mozilla::ThreadLocal sTLSIsMainThread; bool @@ -190,12 +183,6 @@ nsThreadManager::Init() // GetIsMainThread calls that occur post-Shutdown. mMainThread->GetPRThread(&mMainPRThread); -#ifdef XP_WIN - TlsSetValue(gTLSThreadIDIndex, (void*)mozilla::threads::Main); -#elif defined(NS_TLS) - gTLSThreadID = mozilla::threads::Main; -#endif - mInitialized = true; return NS_OK; } diff --git a/xulrunner/installer/Makefile.in b/xulrunner/installer/Makefile.in index cef8ec49d28f..11de3db53e89 100644 --- a/xulrunner/installer/Makefile.in +++ b/xulrunner/installer/Makefile.in @@ -56,7 +56,7 @@ FULL_NSPR_LIBS=$(subst $(prefix),\$${sdkdir},$(shell $(DEPTH)/nsprpub/config/nsp NSPR_VERSION=$(shell $(DEPTH)/nsprpub/config/nspr-config --version) endif -MOZ_XUL_LINK = -lxpcomglue_s -lxul -lmozalloc +MOZ_XUL_LINK = -lxpcomglue_s -lxul ifdef JS_SHARED_LIBRARY MOZ_JS_LINK = -lmozjs else