diff --git a/accessible/base/NotificationController.cpp b/accessible/base/NotificationController.cpp index 1c078a16e08e..ef024cb333b0 100644 --- a/accessible/base/NotificationController.cpp +++ b/accessible/base/NotificationController.cpp @@ -52,7 +52,16 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(NotificationController) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHangingChildDocuments) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContentInsertions) + for (auto it = tmp->mContentInsertions.ConstIter(); !it.Done(); it.Next()) { + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mContentInsertions key"); + cb.NoteXPCOMChild(it.Key()); + nsTArray>* list = it.UserData(); + for (uint32_t i = 0; i < list->Length(); i++) { + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, + "mContentInsertions value item"); + cb.NoteXPCOMChild(list->ElementAt(i)); + } + } NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvents) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRelocations) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END @@ -103,10 +112,23 @@ NotificationController::ScheduleContentInsertion(Accessible* aContainer, nsIContent* aStartChildNode, nsIContent* aEndChildNode) { - RefPtr insertion = new ContentInsertion(mDocument, - aContainer); - if (insertion && insertion->InitChildList(aStartChildNode, aEndChildNode) && - mContentInsertions.AppendElement(insertion)) { + nsTArray>* list = + mContentInsertions.LookupOrAdd(aContainer); + + bool needsProcessing = false; + nsIContent* node = aStartChildNode; + while (node != aEndChildNode) { + // Notification triggers for content insertion even if no content was + // actually inserted, check if the given content has a frame to discard + // this case early. + if (node->GetPrimaryFrame()) { + if (list->AppendElement(node)) + needsProcessing = true; + } + node = node->GetNextSibling(); + } + + if (needsProcessing) { ScheduleProcessing(); } } @@ -130,7 +152,7 @@ NotificationController::IsUpdatePending() { return mPresShell->IsLayoutFlushObserver() || mObservingState == eRefreshProcessingForUpdate || - mContentInsertions.Length() != 0 || mNotifications.Length() != 0 || + mContentInsertions.Count() != 0 || mNotifications.Length() != 0 || mTextHash.Count() != 0 || !mDocument->HasLoadState(DocAccessible::eTreeConstructed); } @@ -178,7 +200,7 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime) mDocument->DoInitialUpdate(); - NS_ASSERTION(mContentInsertions.Length() == 0, + NS_ASSERTION(mContentInsertions.Count() == 0, "Pending content insertions while initial accessible tree isn't created!"); } @@ -196,15 +218,13 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime) // document accessible. // Process only currently queued content inserted notifications. - nsTArray > contentInsertions; - contentInsertions.SwapElements(mContentInsertions); - - uint32_t insertionCount = contentInsertions.Length(); - for (uint32_t idx = 0; idx < insertionCount; idx++) { - contentInsertions[idx]->Process(); - if (!mDocument) + for (auto iter = mContentInsertions.ConstIter(); !iter.Done(); iter.Next()) { + mDocument->ProcessContentInserted(iter.Key(), iter.UserData()); + if (!mDocument) { return; + } } + mContentInsertions.Clear(); // Process rendered text change notifications. for (auto iter = mTextHash.Iter(); !iter.Done(); iter.Next()) { @@ -403,7 +423,7 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime) // Stop further processing if there are no new notifications of any kind or // events and document load is processed. - if (mContentInsertions.IsEmpty() && mNotifications.IsEmpty() && + if (mContentInsertions.Count() == 0 && mNotifications.IsEmpty() && mEvents.IsEmpty() && mTextHash.Count() == 0 && mHangingChildDocuments.IsEmpty() && mDocument->HasLoadState(DocAccessible::eCompletelyLoaded) && @@ -411,53 +431,3 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime) mObservingState = eNotObservingRefresh; } } - -//////////////////////////////////////////////////////////////////////////////// -// NotificationController: content inserted notification - -NotificationController::ContentInsertion:: - ContentInsertion(DocAccessible* aDocument, Accessible* aContainer) : - mDocument(aDocument), mContainer(aContainer) -{ -} - -bool -NotificationController::ContentInsertion:: - InitChildList(nsIContent* aStartChildNode, nsIContent* aEndChildNode) -{ - bool haveToUpdate = false; - - nsIContent* node = aStartChildNode; - while (node != aEndChildNode) { - // Notification triggers for content insertion even if no content was - // actually inserted, check if the given content has a frame to discard - // this case early. - if (node->GetPrimaryFrame()) { - if (mInsertedContent.AppendElement(node)) - haveToUpdate = true; - } - - node = node->GetNextSibling(); - } - - return haveToUpdate; -} - -NS_IMPL_CYCLE_COLLECTION(NotificationController::ContentInsertion, - mContainer) - -NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(NotificationController::ContentInsertion, - AddRef) -NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(NotificationController::ContentInsertion, - Release) - -void -NotificationController::ContentInsertion::Process() -{ - mDocument->ProcessContentInserted(mContainer, &mInsertedContent); - - mDocument = nullptr; - mContainer = nullptr; - mInsertedContent.Clear(); -} - diff --git a/accessible/base/NotificationController.h b/accessible/base/NotificationController.h index 14f7b3af527a..666ddcc4a3f4 100644 --- a/accessible/base/NotificationController.h +++ b/accessible/base/NotificationController.h @@ -247,44 +247,10 @@ private: nsTArray > mHangingChildDocuments; /** - * Storage for content inserted notification information. + * Pending accessible tree update notifications for content insertions. */ - class ContentInsertion - { - public: - ContentInsertion(DocAccessible* aDocument, Accessible* aContainer); - - NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(ContentInsertion) - NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(ContentInsertion) - - bool InitChildList(nsIContent* aStartChildNode, nsIContent* aEndChildNode); - void Process(); - - protected: - virtual ~ContentInsertion() { mDocument = nullptr; } - - private: - ContentInsertion(); - ContentInsertion(const ContentInsertion&); - ContentInsertion& operator = (const ContentInsertion&); - - // The document used to process content insertion, matched to document of - // the notification controller that this notification belongs to, therefore - // it's ok to keep it as weak ref. - DocAccessible* mDocument; - - // The container accessible that content insertion occurs within. - RefPtr mContainer; - - // Array of inserted contents. - nsTArray > mInsertedContent; - }; - - /** - * A pending accessible tree update notifications for content insertions. - * Don't make this an AutoTArray; we use SwapElements() on it. - */ - nsTArray > mContentInsertions; + nsClassHashtable, + nsTArray>> mContentInsertions; template class nsCOMPtrHashKey : public PLDHashEntryHdr @@ -311,7 +277,7 @@ private: }; /** - * A pending accessible tree update notifications for rendered text changes. + * Pending accessible tree update notifications for rendered text changes. */ nsTHashtable > mTextHash; diff --git a/accessible/base/TreeWalker.cpp b/accessible/base/TreeWalker.cpp index e48b1e85e131..cabcf24c1f30 100644 --- a/accessible/base/TreeWalker.cpp +++ b/accessible/base/TreeWalker.cpp @@ -46,7 +46,7 @@ TreeWalker::~TreeWalker() // TreeWalker: private Accessible* -TreeWalker::NextChild() +TreeWalker::Next() { if (mStateStack.IsEmpty()) return nullptr; @@ -82,7 +82,7 @@ TreeWalker::NextChild() top = PushState(parent); if (top->mDOMIter.Seek(mAnchorNode)) { mAnchorNode = parent; - return NextChild(); + return Next(); } // XXX We really should never get here, it means we're trying to find an diff --git a/accessible/base/TreeWalker.h b/accessible/base/TreeWalker.h index 72d3f8dbd7c7..d35c8147ce15 100644 --- a/accessible/base/TreeWalker.h +++ b/accessible/base/TreeWalker.h @@ -44,13 +44,13 @@ public: ~TreeWalker(); /** - * Return the next child accessible. + * Return the next accessible. * * @note Returned accessible is bound to the document, if the accessible is * rejected during tree creation then the caller should be unbind it * from the document. */ - Accessible* NextChild(); + Accessible* Next(); private: TreeWalker(); diff --git a/accessible/base/nsAccessibilityService.cpp b/accessible/base/nsAccessibilityService.cpp index 10b316c39571..e0359c3ebf62 100644 --- a/accessible/base/nsAccessibilityService.cpp +++ b/accessible/base/nsAccessibilityService.cpp @@ -596,7 +596,7 @@ nsAccessibilityService::ContentRemoved(nsIPresShell* aPresShell, Accessible* container = document->GetContainerAccessible(aChildNode); a11y::TreeWalker walker(container ? container : document, aChildNode, a11y::TreeWalker::eWalkCache); - child = walker.NextChild(); + child = walker.Next(); } if (child) { diff --git a/accessible/generic/Accessible.cpp b/accessible/generic/Accessible.cpp index 08486992a8b3..42dc1978d7e2 100644 --- a/accessible/generic/Accessible.cpp +++ b/accessible/generic/Accessible.cpp @@ -2508,7 +2508,7 @@ Accessible::CacheChildren() TreeWalker walker(this, mContent); Accessible* child = nullptr; - while ((child = walker.NextChild()) && AppendChild(child)); + while ((child = walker.Next()) && AppendChild(child)); } void diff --git a/accessible/generic/DocAccessible.cpp b/accessible/generic/DocAccessible.cpp index 4a8b57369071..3c9e675a5907 100644 --- a/accessible/generic/DocAccessible.cpp +++ b/accessible/generic/DocAccessible.cpp @@ -1433,7 +1433,7 @@ DocAccessible::CacheChildren() // Ignore last HTML:br, copied from HyperTextAccessible. TreeWalker walker(this, rootElm); Accessible* lastChild = nullptr; - while (Accessible* child = walker.NextChild()) { + while (Accessible* child = walker.Next()) { if (lastChild) AppendChild(lastChild); diff --git a/accessible/generic/HyperTextAccessible.cpp b/accessible/generic/HyperTextAccessible.cpp index e0da87515bec..057ed580d834 100644 --- a/accessible/generic/HyperTextAccessible.cpp +++ b/accessible/generic/HyperTextAccessible.cpp @@ -284,7 +284,7 @@ HyperTextAccessible::DOMPointToOffset(nsINode* aNode, int32_t aNodeOffset, if (container) { TreeWalker walker(container, findNode->AsContent(), TreeWalker::eWalkContextTree); - descendant = walker.NextChild(); + descendant = walker.Next(); if (!descendant) descendant = container; } @@ -1945,7 +1945,7 @@ HyperTextAccessible::CacheChildren() TreeWalker walker(this, mContent); Accessible* child = nullptr; Accessible* lastChild = nullptr; - while ((child = walker.NextChild())) { + while ((child = walker.Next())) { if (lastChild) AppendChild(lastChild); diff --git a/accessible/html/HTMLTableAccessible.cpp b/accessible/html/HTMLTableAccessible.cpp index 247687f3988a..5a8de9ff0bc2 100644 --- a/accessible/html/HTMLTableAccessible.cpp +++ b/accessible/html/HTMLTableAccessible.cpp @@ -403,10 +403,10 @@ HTMLTableAccessible::CacheChildren() TreeWalker walker(this, mContent); Accessible* child = nullptr; - while ((child = walker.NextChild())) { + while ((child = walker.Next())) { if (child->Role() == roles::CAPTION) { InsertChildAt(0, child); - while ((child = walker.NextChild()) && AppendChild(child)); + while ((child = walker.Next()) && AppendChild(child)); break; } AppendChild(child); diff --git a/browser/base/content/browser-places.js b/browser/base/content/browser-places.js index e4f85e14db78..758348797afc 100644 --- a/browser/base/content/browser-places.js +++ b/browser/base/content/browser-places.js @@ -1878,44 +1878,3 @@ var BookmarkingUI = { Ci.nsINavBookmarkObserver ]) }; - -var AutoShowBookmarksToolbar = { - init() { - PlacesUtils.addLazyBookmarkObserver(this, false); - }, - - uninit() { - PlacesUtils.removeLazyBookmarkObserver(this); - }, - - onItemAdded(aItemId, aParentId, aIndex, aItemType, aURI, aTitle, aDateAdded, - aGuid, aParentGuid) { - this._autoshow(aParentGuid); - }, - onBeginUpdateBatch() {}, - onEndUpdateBatch() {}, - onItemRemoved() {}, - onItemChanged() {}, - onItemVisited() {}, - onItemMoved(aItemId, aOldParent, aOldIndex, aNewParent, aNewIndex, aItemType, - aGuid, aOldParentGuid, aNewParentGuid) { - this._autoshow(aNewParentGuid); - }, - - _autoshow(aParentGuid) { - if (aParentGuid != PlacesUtils.bookmarks.toolbarGuid) - return; - - let toolbar = document.getElementById("PersonalToolbar"); - if (!toolbar.collapsed) - return; - - let placement = CustomizableUI.getPlacementOfWidget("personal-bookmarks"); - let area = placement && placement.area; - if (area != CustomizableUI.AREA_BOOKMARKS) - return; - - setToolbarVisibility(toolbar, true); - } -}; - diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 7af65096c3c1..5fad880b0dec 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -1200,7 +1200,6 @@ var gBrowserInit = { gBrowser.tabContainer.updateVisibility(); BookmarkingUI.init(); - AutoShowBookmarksToolbar.init(); gPrefService.addObserver(gHomeButton.prefDomain, gHomeButton, false); @@ -1504,7 +1503,6 @@ var gBrowserInit = { IndexedDBPromptHelper.uninit(); LightweightThemeListener.uninit(); PanelUI.uninit(); - AutoShowBookmarksToolbar.uninit(); } // Final window teardown, do this last. @@ -4715,7 +4713,8 @@ nsBrowserAccess.prototype = { QueryInterface: XPCOMUtils.generateQI([Ci.nsIBrowserDOMWindow, Ci.nsISupports]), _openURIInNewTab: function(aURI, aReferrer, aReferrerPolicy, aIsPrivate, - aIsExternal, aForceNotRemote=false) { + aIsExternal, aForceNotRemote=false, + aUserContextId=Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID) { let win, needToFocusWin; // try the current window. if we're in a popup, fall back on the most recent browser window @@ -4742,6 +4741,7 @@ nsBrowserAccess.prototype = { let tab = win.gBrowser.loadOneTab(aURI ? aURI.spec : "about:blank", { referrerURI: aReferrer, referrerPolicy: aReferrerPolicy, + userContextId: aUserContextId, fromExternal: aIsExternal, inBackground: loadInBackground, forceNotRemote: aForceNotRemote}); @@ -4814,9 +4814,12 @@ nsBrowserAccess.prototype = { // will do the job of shuttling off the newly opened browser to run in // the right process once it starts loading a URI. let forceNotRemote = !!aOpener; + let userContextId = aOpener && aOpener.document + ? aOpener.document.nodePrincipal.originAttributes.userContextId + : Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID; let browser = this._openURIInNewTab(aURI, referrer, referrerPolicy, isPrivate, isExternal, - forceNotRemote); + forceNotRemote, userContextId); if (browser) newWindow = browser.contentWindow; break; @@ -4845,9 +4848,17 @@ nsBrowserAccess.prototype = { } var isExternal = (aContext == Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL); + + var userContextId = aParams.openerOriginAttributes && + ("userContextId" in aParams.openerOriginAttributes) + ? aParams.openerOriginAttributes.userContextId + : Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID + let browser = this._openURIInNewTab(aURI, aParams.referrer, aParams.referrerPolicy, - aParams.isPrivate, isExternal); + aParams.isPrivate, + isExternal, false, + userContextId); if (browser) return browser.QueryInterface(Ci.nsIFrameLoaderOwner); diff --git a/build/templates.mozbuild b/build/templates.mozbuild index 157915f664ad..d4fd979c35f6 100644 --- a/build/templates.mozbuild +++ b/build/templates.mozbuild @@ -90,11 +90,17 @@ def HostStdCppCompat(): @template -def HostProgram(name): +def HostProgram(name, c_only=False): '''Template for build tools executables.''' HOST_PROGRAM = name - HostStdCppCompat() + # With context-based templates, this won't be needed anymore, and will + # work better than relying on the caller setting it, but at the moment, + # this is the best we have. And it doesn't matter /that/ much, so there's + # really only one place using this, where it does matter to avoid the + # extra dependency (because it creates a circular one). + if not c_only: + HostStdCppCompat() @template diff --git a/config/moz.build b/config/moz.build index 269a6c76a922..f40a72530065 100644 --- a/config/moz.build +++ b/config/moz.build @@ -24,7 +24,10 @@ if CONFIG['HOST_OS_ARCH'] != 'WINNT': 'nsinstall.c', 'pathsub.c', ] - HostProgram('nsinstall_real') + # stdc++compat depends on config/export, so avoid a circular + # dependency added by HostProgram depending on stdc++compat, + # while the program here is in C. + HostProgram('nsinstall_real', c_only=True) if CONFIG['MOZ_SHARED_ICU']: DEFINES['MOZ_SHARED_ICU'] = True diff --git a/config/recurse.mk b/config/recurse.mk index 4a59b775cc13..6316f7c27f72 100644 --- a/config/recurse.mk +++ b/config/recurse.mk @@ -152,7 +152,7 @@ widget/android/bindings/export: build/annotationProcessors/export mobile/android/tests/browser/robocop/roboextender/tools: mobile/android/tests/javaaddons/tools ifdef ENABLE_CLANG_PLUGIN -$(filter-out build/clang-plugin/%,$(compile_targets)): build/clang-plugin/target build/clang-plugin/tests/target +$(filter-out config/host build/unix/stdc++compat/% build/clang-plugin/%,$(compile_targets)): build/clang-plugin/target build/clang-plugin/tests/target build/clang-plugin/tests/target: build/clang-plugin/target endif @@ -176,3 +176,6 @@ endif # happen at the same time (bug #1146738) js/src/target: js/src/host endif +# Most things are built during compile (target/host), but some things happen during export +# Those need to depend on config/export for system wrappers. +$(addprefix build/unix/stdc++compat/,target host) build/clang-plugin/target: config/export diff --git a/config/rules.mk b/config/rules.mk index ca2a58f3d4e9..e40e1792b5d2 100644 --- a/config/rules.mk +++ b/config/rules.mk @@ -863,9 +863,6 @@ endif # WINNT && !GCC ifdef ENABLE_STRIP $(STRIP) $(STRIP_FLAGS) $@ endif -ifdef MOZ_POST_DSO_LIB_COMMAND - $(MOZ_POST_DSO_LIB_COMMAND) $@ -endif ifeq ($(SOLARIS_SUNPRO_CC),1) _MDDEPFILE = $(MDDEPDIR)/$(@F).pp diff --git a/configure.in b/configure.in index bef32fce9faa..d74d2f43ec83 100644 --- a/configure.in +++ b/configure.in @@ -8475,7 +8475,6 @@ AC_SUBST(USE_DEPENDENT_LIBS) AC_SUBST(MOZ_BUILD_ROOT) -AC_SUBST(MOZ_POST_DSO_LIB_COMMAND) AC_SUBST(MOZ_POST_PROGRAM_COMMAND) AC_SUBST(MOZ_LINKER_EXTRACT) diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 3df3473a3ca0..2e5ce9e73ff4 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -5814,6 +5814,15 @@ nsDocShell::SetPosition(int32_t aX, int32_t aY) return NS_OK; } +NS_IMETHODIMP +nsDocShell::SetPositionDesktopPix(int32_t aX, int32_t aY) +{ + // Added to nsIBaseWindow in bug 1247335; + // implement if a use-case is found. + NS_ASSERTION(false, "implement me!"); + return NS_ERROR_NOT_IMPLEMENTED; +} + NS_IMETHODIMP nsDocShell::GetPosition(int32_t* aX, int32_t* aY) { diff --git a/dom/animation/Animation.cpp b/dom/animation/Animation.cpp index e57c1b4882ad..b113aae92434 100644 --- a/dom/animation/Animation.cpp +++ b/dom/animation/Animation.cpp @@ -1107,7 +1107,7 @@ Animation::PostUpdate() } Element* targetElement; - nsCSSPseudoElements::Type targetPseudoType; + CSSPseudoElementType targetPseudoType; mEffect->GetTarget(targetElement, targetPseudoType); if (!targetElement) { return; @@ -1204,8 +1204,7 @@ Animation::EffectEnd() const return StickyTimeDuration(0); } - return mEffect->SpecifiedTiming().mDelay - + mEffect->GetComputedTiming().mActiveDuration; + return mEffect->GetComputedTiming().mEndTime; } nsIDocument* diff --git a/dom/animation/CSSPseudoElement.cpp b/dom/animation/CSSPseudoElement.cpp index 8bf8606cbe3b..e27f3d646aa6 100644 --- a/dom/animation/CSSPseudoElement.cpp +++ b/dom/animation/CSSPseudoElement.cpp @@ -17,13 +17,13 @@ NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(CSSPseudoElement, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(CSSPseudoElement, Release) CSSPseudoElement::CSSPseudoElement(Element* aElement, - nsCSSPseudoElements::Type aType) + CSSPseudoElementType aType) : mParentElement(aElement) , mPseudoType(aType) { MOZ_ASSERT(aElement); - MOZ_ASSERT(aType == nsCSSPseudoElements::ePseudo_after || - aType == nsCSSPseudoElements::ePseudo_before, + MOZ_ASSERT(aType == CSSPseudoElementType::after || + aType == CSSPseudoElementType::before, "Unexpected Pseudo Type"); } @@ -69,7 +69,7 @@ CSSPseudoElement::Animate( /* static */ already_AddRefed CSSPseudoElement::GetCSSPseudoElement(Element* aElement, - nsCSSPseudoElements::Type aType) + CSSPseudoElementType aType) { if (!aElement) { return nullptr; @@ -96,14 +96,13 @@ CSSPseudoElement::GetCSSPseudoElement(Element* aElement, } /* static */ nsIAtom* -CSSPseudoElement::GetCSSPseudoElementPropertyAtom( - nsCSSPseudoElements::Type aType) +CSSPseudoElement::GetCSSPseudoElementPropertyAtom(CSSPseudoElementType aType) { switch (aType) { - case nsCSSPseudoElements::ePseudo_before: + case CSSPseudoElementType::before: return nsGkAtoms::cssPseudoElementBeforeProperty; - case nsCSSPseudoElements::ePseudo_after: + case CSSPseudoElementType::after: return nsGkAtoms::cssPseudoElementAfterProperty; default: diff --git a/dom/animation/CSSPseudoElement.h b/dom/animation/CSSPseudoElement.h index 9428187ccab8..ee4107ef390b 100644 --- a/dom/animation/CSSPseudoElement.h +++ b/dom/animation/CSSPseudoElement.h @@ -38,7 +38,7 @@ public: virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; - nsCSSPseudoElements::Type GetType() const { return mPseudoType; } + CSSPseudoElementType GetType() const { return mPseudoType; } void GetType(nsString& aRetVal) const { MOZ_ASSERT(nsCSSPseudoElements::GetPseudoAtom(mPseudoType), @@ -64,20 +64,19 @@ public: // pseudo-type on element, a new CSSPseudoElement will be created and stored // on the element. static already_AddRefed - GetCSSPseudoElement(Element* aElement, nsCSSPseudoElements::Type aType); + GetCSSPseudoElement(Element* aElement, CSSPseudoElementType aType); private: // Only ::before and ::after are supported. - CSSPseudoElement(Element* aElement, nsCSSPseudoElements::Type aType); + CSSPseudoElement(Element* aElement, CSSPseudoElementType aType); - static nsIAtom* - GetCSSPseudoElementPropertyAtom(nsCSSPseudoElements::Type aType); + static nsIAtom* GetCSSPseudoElementPropertyAtom(CSSPseudoElementType aType); // mParentElement needs to be an owning reference since if script is holding // on to the pseudo-element, it needs to continue to be able to refer to // the parent element. RefPtr mParentElement; - nsCSSPseudoElements::Type mPseudoType; + CSSPseudoElementType mPseudoType; }; } // namespace dom diff --git a/dom/animation/EffectCompositor.cpp b/dom/animation/EffectCompositor.cpp index d4a11200d5d5..4dcad3ef2b94 100644 --- a/dom/animation/EffectCompositor.cpp +++ b/dom/animation/EffectCompositor.cpp @@ -16,6 +16,7 @@ #include "nsComputedDOMStyle.h" // nsComputedDOMStyle::GetPresShellForContent #include "nsCSSPropertySet.h" #include "nsCSSProps.h" +#include "nsCSSPseudoElements.h" #include "nsIPresShell.h" #include "nsLayoutUtils.h" #include "nsRuleNode.h" // For nsRuleNode::ComputePropertiesOverridingAnimation @@ -80,7 +81,7 @@ FindAnimationsForCompositor(const nsIFrame* aFrame, // Those cases are probably not important but just to be safe, let's make // sure the cascade is up to date since if it *is* up to date, this is // basically a no-op. - Maybe> pseudoElement = + Maybe> pseudoElement = EffectCompositor::GetAnimationElementAndPseudoForFrame(aFrame); if (pseudoElement) { EffectCompositor::MaybeUpdateCascadeResults(pseudoElement->first(), @@ -131,7 +132,7 @@ FindAnimationsForCompositor(const nsIFrame* aFrame, void EffectCompositor::RequestRestyle(dom::Element* aElement, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, RestyleType aRestyleType, CascadeLevel aCascadeLevel) { @@ -171,7 +172,7 @@ EffectCompositor::RequestRestyle(dom::Element* aElement, void EffectCompositor::PostRestyleForAnimation(dom::Element* aElement, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, CascadeLevel aCascadeLevel) { if (!mPresContext) { @@ -212,8 +213,7 @@ EffectCompositor::PostRestyleForThrottledAnimations() void EffectCompositor::MaybeUpdateAnimationRule(dom::Element* aElement, - nsCSSPseudoElements::Type - aPseudoType, + CSSPseudoElementType aPseudoType, CascadeLevel aCascadeLevel) { // First update cascade results since that may cause some elements to @@ -235,7 +235,7 @@ EffectCompositor::MaybeUpdateAnimationRule(dom::Element* aElement, nsIStyleRule* EffectCompositor::GetAnimationRule(dom::Element* aElement, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, CascadeLevel aCascadeLevel) { // NOTE: We need to be careful about early returns in this method where @@ -281,9 +281,9 @@ EffectCompositor::GetAnimationRule(dom::Element* aElement, /* static */ dom::Element* EffectCompositor::GetElementToRestyle(dom::Element* aElement, - nsCSSPseudoElements::Type aPseudoType) + CSSPseudoElementType aPseudoType) { - if (aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) { + if (aPseudoType == CSSPseudoElementType::NotPseudo) { return aElement; } @@ -292,9 +292,9 @@ EffectCompositor::GetElementToRestyle(dom::Element* aElement, return nullptr; } nsIFrame* pseudoFrame; - if (aPseudoType == nsCSSPseudoElements::ePseudo_before) { + if (aPseudoType == CSSPseudoElementType::before) { pseudoFrame = nsLayoutUtils::GetBeforeFrame(primaryFrame); - } else if (aPseudoType == nsCSSPseudoElements::ePseudo_after) { + } else if (aPseudoType == CSSPseudoElementType::after) { pseudoFrame = nsLayoutUtils::GetAfterFrame(primaryFrame); } else { NS_NOTREACHED("Should not try to get the element to restyle for a pseudo " @@ -417,8 +417,7 @@ EffectCompositor::ClearIsRunningOnCompositor(const nsIFrame *aFrame, /* static */ void EffectCompositor::MaybeUpdateCascadeResults(Element* aElement, - nsCSSPseudoElements::Type - aPseudoType, + CSSPseudoElementType aPseudoType, nsStyleContext* aStyleContext) { EffectSet* effects = EffectSet::GetEffectSet(aElement, aPseudoType); @@ -433,8 +432,7 @@ EffectCompositor::MaybeUpdateCascadeResults(Element* aElement, /* static */ void EffectCompositor::MaybeUpdateCascadeResults(Element* aElement, - nsCSSPseudoElements::Type - aPseudoType) + CSSPseudoElementType aPseudoType) { nsStyleContext* styleContext = nullptr; { @@ -474,7 +472,7 @@ namespace { /* static */ void EffectCompositor::UpdateCascadeResults(Element* aElement, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, nsStyleContext* aStyleContext) { EffectSet* effects = EffectSet::GetEffectSet(aElement, aPseudoType); @@ -485,19 +483,18 @@ EffectCompositor::UpdateCascadeResults(Element* aElement, UpdateCascadeResults(*effects, aElement, aPseudoType, aStyleContext); } -/* static */ Maybe> +/* static */ Maybe> EffectCompositor::GetAnimationElementAndPseudoForFrame(const nsIFrame* aFrame) { // Always return the same object to benefit from return-value optimization. - Maybe> result; + Maybe> result; nsIContent* content = aFrame->GetContent(); if (!content) { return result; } - nsCSSPseudoElements::Type pseudoType = - nsCSSPseudoElements::ePseudo_NotPseudoElement; + CSSPseudoElementType pseudoType = CSSPseudoElementType::NotPseudo; if (aFrame->IsGeneratedContentFrame()) { nsIFrame* parent = aFrame->GetParent(); @@ -506,9 +503,9 @@ EffectCompositor::GetAnimationElementAndPseudoForFrame(const nsIFrame* aFrame) } nsIAtom* name = content->NodeInfo()->NameAtom(); if (name == nsGkAtoms::mozgeneratedcontentbefore) { - pseudoType = nsCSSPseudoElements::ePseudo_before; + pseudoType = CSSPseudoElementType::before; } else if (name == nsGkAtoms::mozgeneratedcontentafter) { - pseudoType = nsCSSPseudoElements::ePseudo_after; + pseudoType = CSSPseudoElementType::after; } else { return result; } @@ -534,7 +531,7 @@ EffectCompositor::GetAnimationElementAndPseudoForFrame(const nsIFrame* aFrame) /* static */ void EffectCompositor::ComposeAnimationRule(dom::Element* aElement, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, CascadeLevel aCascadeLevel, TimeStamp aRefreshTime) { @@ -615,7 +612,7 @@ EffectCompositor::GetOverriddenProperties(nsStyleContext* aStyleContext, /* static */ void EffectCompositor::UpdateCascadeResults(EffectSet& aEffectSet, Element* aElement, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, nsStyleContext* aStyleContext) { MOZ_ASSERT(EffectSet::GetEffectSet(aElement, aPseudoType) == &aEffectSet, @@ -763,7 +760,7 @@ EffectCompositor::AnimationStyleRuleProcessor::RulesMatching( { nsIStyleRule *rule = mCompositor->GetAnimationRule(aData->mElement, - nsCSSPseudoElements::ePseudo_NotPseudoElement, + CSSPseudoElementType::NotPseudo, mCascadeLevel); if (rule) { aData->mRuleWalker->Forward(rule); @@ -775,8 +772,8 @@ void EffectCompositor::AnimationStyleRuleProcessor::RulesMatching( PseudoElementRuleProcessorData* aData) { - if (aData->mPseudoType != nsCSSPseudoElements::ePseudo_before && - aData->mPseudoType != nsCSSPseudoElements::ePseudo_after) { + if (aData->mPseudoType != CSSPseudoElementType::before && + aData->mPseudoType != CSSPseudoElementType::after) { return; } diff --git a/dom/animation/EffectCompositor.h b/dom/animation/EffectCompositor.h index 5f21ae3e651b..679fbf337471 100644 --- a/dom/animation/EffectCompositor.h +++ b/dom/animation/EffectCompositor.h @@ -14,7 +14,6 @@ #include "mozilla/PseudoElementHashEntry.h" #include "mozilla/RefPtr.h" #include "nsCSSProperty.h" -#include "nsCSSPseudoElements.h" #include "nsCycleCollectionParticipant.h" #include "nsDataHashtable.h" #include "nsIStyleRuleProcessor.h" @@ -30,6 +29,7 @@ namespace mozilla { class EffectSet; class RestyleTracker; +enum class CSSPseudoElementType : uint8_t; namespace dom { class Animation; @@ -94,7 +94,7 @@ public: // The specified steps taken to update the animation rule depend on // |aRestyleType| whose values are described above. void RequestRestyle(dom::Element* aElement, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, RestyleType aRestyleType, CascadeLevel aCascadeLevel); @@ -103,7 +103,7 @@ public: // need to perform this step when triggering transitions *without* also // invalidating the animation style rule (which RequestRestyle would do). void PostRestyleForAnimation(dom::Element* aElement, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, CascadeLevel aCascadeLevel); // Posts an animation restyle for any elements whose animation style rule @@ -116,11 +116,11 @@ public: // If the animation rule is not marked as needing an update, // no work is done. void MaybeUpdateAnimationRule(dom::Element* aElement, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, CascadeLevel aCascadeLevel); nsIStyleRule* GetAnimationRule(dom::Element* aElement, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, CascadeLevel aCascadeLevel); bool HasPendingStyleUpdates() const; @@ -155,14 +155,14 @@ public: // animation level of the cascade have changed. static void MaybeUpdateCascadeResults(dom::Element* aElement, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, nsStyleContext* aStyleContext); // An overload of MaybeUpdateCascadeResults that uses the style context // of the primary frame of the specified (pseudo-)element, when available. static void MaybeUpdateCascadeResults(dom::Element* aElement, - nsCSSPseudoElements::Type aPseudoType); + CSSPseudoElementType aPseudoType); // Update the mWinsInCascade member for each property in effects targetting // the specified (pseudo-)element. @@ -172,7 +172,7 @@ public: // other cases we should call MaybeUpdateCascadeResults. static void UpdateCascadeResults(dom::Element* aElement, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, nsStyleContext* aStyleContext); // Helper to fetch the corresponding element and pseudo-type from a frame. @@ -184,7 +184,7 @@ public: // Returns an empty result when a suitable element cannot be found including // when the frame represents a pseudo-element on which we do not support // animations. - static Maybe> + static Maybe> GetAnimationElementAndPseudoForFrame(const nsIFrame* aFrame); private: @@ -193,12 +193,12 @@ private: // Rebuilds the animation rule corresponding to |aCascadeLevel| on the // EffectSet associated with the specified (pseudo-)element. static void ComposeAnimationRule(dom::Element* aElement, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, CascadeLevel aCascadeLevel, TimeStamp aRefreshTime); static dom::Element* GetElementToRestyle(dom::Element* aElement, - nsCSSPseudoElements::Type + CSSPseudoElementType aPseudoType); // Get the properties in |aEffectSet| that we are able to animate on the @@ -212,7 +212,7 @@ private: static void UpdateCascadeResults(EffectSet& aEffectSet, dom::Element* aElement, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, nsStyleContext* aStyleContext); static nsPresContext* GetPresContext(dom::Element* aElement); diff --git a/dom/animation/EffectSet.cpp b/dom/animation/EffectSet.cpp index 1af88580bf1f..04dbeba4ba24 100644 --- a/dom/animation/EffectSet.cpp +++ b/dom/animation/EffectSet.cpp @@ -7,6 +7,7 @@ #include "EffectSet.h" #include "mozilla/dom/Element.h" // For Element #include "RestyleManager.h" +#include "nsCSSPseudoElements.h" // For CSSPseudoElementType #include "nsCycleCollectionNoteChild.h" // For CycleCollectionNoteChild #include "nsPresContext.h" #include "nsLayoutUtils.h" @@ -38,7 +39,7 @@ EffectSet::Traverse(nsCycleCollectionTraversalCallback& aCallback) /* static */ EffectSet* EffectSet::GetEffectSet(dom::Element* aElement, - nsCSSPseudoElements::Type aPseudoType) + CSSPseudoElementType aPseudoType) { nsIAtom* propName = GetEffectSetPropertyAtom(aPseudoType); return static_cast(aElement->GetProperty(propName)); @@ -87,7 +88,7 @@ EffectSet::GetEffectSet(const nsIFrame* aFrame) /* static */ EffectSet* EffectSet::GetOrCreateEffectSet(dom::Element* aElement, - nsCSSPseudoElements::Type aPseudoType) + CSSPseudoElementType aPseudoType) { EffectSet* effectSet = GetEffectSet(aElement, aPseudoType); if (effectSet) { @@ -114,7 +115,7 @@ EffectSet::GetOrCreateEffectSet(dom::Element* aElement, /* static */ void EffectSet::DestroyEffectSet(dom::Element* aElement, - nsCSSPseudoElements::Type aPseudoType) + CSSPseudoElementType aPseudoType) { nsIAtom* propName = GetEffectSetPropertyAtom(aPseudoType); EffectSet* effectSet = @@ -152,16 +153,16 @@ EffectSet::GetEffectSetPropertyAtoms() } /* static */ nsIAtom* -EffectSet::GetEffectSetPropertyAtom(nsCSSPseudoElements::Type aPseudoType) +EffectSet::GetEffectSetPropertyAtom(CSSPseudoElementType aPseudoType) { switch (aPseudoType) { - case nsCSSPseudoElements::ePseudo_NotPseudoElement: + case CSSPseudoElementType::NotPseudo: return nsGkAtoms::animationEffectsProperty; - case nsCSSPseudoElements::ePseudo_before: + case CSSPseudoElementType::before: return nsGkAtoms::animationEffectsForBeforeProperty; - case nsCSSPseudoElements::ePseudo_after: + case CSSPseudoElementType::after: return nsGkAtoms::animationEffectsForAfterProperty; default: diff --git a/dom/animation/EffectSet.h b/dom/animation/EffectSet.h index e1277658f3f4..4d1ecf8b16cf 100644 --- a/dom/animation/EffectSet.h +++ b/dom/animation/EffectSet.h @@ -12,7 +12,6 @@ #include "mozilla/EffectCompositor.h" #include "mozilla/EnumeratedArray.h" #include "mozilla/TimeStamp.h" -#include "nsCSSPseudoElements.h" // For nsCSSPseudoElements::Type #include "nsHashKeys.h" // For nsPtrHashKey #include "nsTHashtable.h" // For nsTHashtable @@ -25,6 +24,8 @@ class Element; class KeyframeEffectReadOnly; } // namespace dom +enum class CSSPseudoElementType : uint8_t; + // A wrapper around a hashset of AnimationEffect objects to handle // storing the set as a property of an element. class EffectSet @@ -57,12 +58,12 @@ public: void Traverse(nsCycleCollectionTraversalCallback& aCallback); static EffectSet* GetEffectSet(dom::Element* aElement, - nsCSSPseudoElements::Type aPseudoType); + CSSPseudoElementType aPseudoType); static EffectSet* GetEffectSet(const nsIFrame* aFrame); static EffectSet* GetOrCreateEffectSet(dom::Element* aElement, - nsCSSPseudoElements::Type aPseudoType); + CSSPseudoElementType aPseudoType); static void DestroyEffectSet(dom::Element* aElement, - nsCSSPseudoElements::Type aPseudoType); + CSSPseudoElementType aPseudoType); void AddEffect(dom::KeyframeEffectReadOnly& aEffect); void RemoveEffect(dom::KeyframeEffectReadOnly& aEffect); @@ -182,8 +183,7 @@ public: static nsIAtom** GetEffectSetPropertyAtoms(); private: - static nsIAtom* GetEffectSetPropertyAtom(nsCSSPseudoElements::Type - aPseudoType); + static nsIAtom* GetEffectSetPropertyAtom(CSSPseudoElementType aPseudoType); OwningEffectSet mEffects; diff --git a/dom/animation/KeyframeEffect.cpp b/dom/animation/KeyframeEffect.cpp index 82fb7679d725..74844634be3c 100644 --- a/dom/animation/KeyframeEffect.cpp +++ b/dom/animation/KeyframeEffect.cpp @@ -17,6 +17,7 @@ #include "nsCSSParser.h" #include "nsCSSPropertySet.h" #include "nsCSSProps.h" // For nsCSSProps::PropHasFlags +#include "nsCSSPseudoElements.h" #include "nsCSSValue.h" #include "nsStyleUtil.h" #include // For std::max @@ -40,8 +41,7 @@ GetComputedTimingDictionary(const ComputedTiming& aComputedTiming, // ComputedTimingProperties aRetVal.mActiveDuration = aComputedTiming.mActiveDuration.ToMilliseconds(); - aRetVal.mEndTime - = std::max(aRetVal.mDelay + aRetVal.mActiveDuration + aRetVal.mEndDelay, 0.0); + aRetVal.mEndTime = aComputedTiming.mEndTime.ToMilliseconds(); aRetVal.mLocalTime = AnimationUtils::TimeDurationToDouble(aLocalTime); aRetVal.mProgress = aComputedTiming.mProgress; if (!aRetVal.mProgress.IsNull()) { @@ -74,7 +74,7 @@ NS_IMPL_RELEASE_INHERITED(KeyframeEffectReadOnly, AnimationEffectReadOnly) KeyframeEffectReadOnly::KeyframeEffectReadOnly( nsIDocument* aDocument, Element* aTarget, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, const TimingParams& aTiming) : KeyframeEffectReadOnly(aDocument, aTarget, aPseudoType, new AnimationEffectTimingReadOnly(aTiming)) @@ -84,7 +84,7 @@ KeyframeEffectReadOnly::KeyframeEffectReadOnly( KeyframeEffectReadOnly::KeyframeEffectReadOnly( nsIDocument* aDocument, Element* aTarget, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, AnimationEffectTimingReadOnly* aTiming) : AnimationEffectReadOnly(aDocument) , mTarget(aTarget) @@ -244,6 +244,8 @@ KeyframeEffectReadOnly::GetComputedTimingAt( 1.0f : aTiming.mIterations; result.mActiveDuration = ActiveDuration(result.mDuration, result.mIterations); + // Bug 1244635: Add endDelay to the end time calculation + result.mEndTime = aTiming.mDelay + result.mActiveDuration; result.mFill = aTiming.mFill == dom::FillMode::Auto ? dom::FillMode::None : aTiming.mFill; @@ -366,18 +368,19 @@ KeyframeEffectReadOnly::GetComputedTimingAt( } StickyTimeDuration -KeyframeEffectReadOnly::ActiveDuration(const StickyTimeDuration& aIterationDuration, - double aIterationCount) +KeyframeEffectReadOnly::ActiveDuration( + const StickyTimeDuration& aIterationDuration, + double aIterationCount) { - if (IsInfinite(aIterationCount)) { - // An animation that repeats forever has an infinite active duration - // unless its iteration duration is zero, in which case it has a zero - // active duration. - const StickyTimeDuration zeroDuration; - return aIterationDuration == zeroDuration ? - zeroDuration : - StickyTimeDuration::Forever(); + // If either the iteration duration or iteration count is zero, + // Web Animations says that the active duration is zero. This is to + // ensure that the result is defined when the other argument is Infinity. + const StickyTimeDuration zeroDuration; + if (aIterationDuration == zeroDuration || + aIterationCount == 0.0) { + return zeroDuration; } + return aIterationDuration.MultDouble(aIterationCount); } @@ -624,8 +627,7 @@ KeyframeEffectReadOnly::ConstructKeyframeEffect(const GlobalObject& aGlobal, "Uninitialized target"); RefPtr targetElement; - nsCSSPseudoElements::Type pseudoType = - nsCSSPseudoElements::ePseudo_NotPseudoElement; + CSSPseudoElementType pseudoType = CSSPseudoElementType::NotPseudo; if (target.IsElement()) { targetElement = &target.GetAsElement(); } else { @@ -1230,7 +1232,7 @@ ApplyDistributeSpacing(nsTArray& aKeyframes) */ static void GenerateValueEntries(Element* aTarget, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, nsTArray& aKeyframes, nsTArray& aResult, ErrorResult& aRv) @@ -1434,7 +1436,7 @@ static void BuildAnimationPropertyListFromKeyframeSequence( JSContext* aCx, Element* aTarget, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, JS::ForOfIterator& aIterator, nsTArray& aResult, ErrorResult& aRv) @@ -1492,7 +1494,7 @@ static void BuildAnimationPropertyListFromPropertyIndexedKeyframes( JSContext* aCx, Element* aTarget, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, JS::Handle aValue, InfallibleTArray& aResult, ErrorResult& aRv) @@ -1667,7 +1669,7 @@ BuildAnimationPropertyListFromPropertyIndexedKeyframes( KeyframeEffectReadOnly::BuildAnimationPropertyList( JSContext* aCx, Element* aTarget, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, JS::Handle aFrames, InfallibleTArray& aResult, ErrorResult& aRv) @@ -1721,13 +1723,13 @@ KeyframeEffectReadOnly::GetTarget( } switch (mPseudoType) { - case nsCSSPseudoElements::ePseudo_before: - case nsCSSPseudoElements::ePseudo_after: + case CSSPseudoElementType::before: + case CSSPseudoElementType::after: aRv.SetValue().SetAsCSSPseudoElement() = CSSPseudoElement::GetCSSPseudoElement(mTarget, mPseudoType); break; - case nsCSSPseudoElements::ePseudo_NotPseudoElement: + case CSSPseudoElementType::NotPseudo: aRv.SetValue().SetAsElement() = mTarget; break; @@ -1975,12 +1977,12 @@ KeyframeEffectReadOnly::GetAnimationFrame() const return nullptr; } - if (mPseudoType == nsCSSPseudoElements::ePseudo_before) { + if (mPseudoType == CSSPseudoElementType::before) { frame = nsLayoutUtils::GetBeforeFrame(frame); - } else if (mPseudoType == nsCSSPseudoElements::ePseudo_after) { + } else if (mPseudoType == CSSPseudoElementType::after) { frame = nsLayoutUtils::GetAfterFrame(frame); } else { - MOZ_ASSERT(mPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement, + MOZ_ASSERT(mPseudoType == CSSPseudoElementType::NotPseudo, "unknown mPseudoType"); } if (!frame) { @@ -2126,7 +2128,7 @@ KeyframeEffectReadOnly::ShouldBlockCompositorAnimations(const nsIFrame* KeyframeEffect::KeyframeEffect(nsIDocument* aDocument, Element* aTarget, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, const TimingParams& aTiming) : KeyframeEffectReadOnly(aDocument, aTarget, aPseudoType, new AnimationEffectTiming(aTiming)) diff --git a/dom/animation/KeyframeEffect.h b/dom/animation/KeyframeEffect.h index 53be0c96cb17..f4c9d8fc2f88 100644 --- a/dom/animation/KeyframeEffect.h +++ b/dom/animation/KeyframeEffect.h @@ -9,7 +9,6 @@ #include "nsAutoPtr.h" #include "nsCycleCollectionParticipant.h" -#include "nsCSSPseudoElements.h" #include "nsIDocument.h" #include "nsWrapperCache.h" #include "mozilla/Attributes.h" @@ -38,6 +37,7 @@ namespace mozilla { struct AnimationCollection; class AnimValuesStyleRule; +enum class CSSPseudoElementType : uint8_t; namespace dom { class ElementOrCSSPseudoElement; @@ -57,6 +57,10 @@ struct ComputedTiming // Will equal StickyTimeDuration::Forever() if the animation repeats // indefinitely. StickyTimeDuration mActiveDuration; + // The effect end time in local time (i.e. an offset from the effect's + // start time). Will equal StickyTimeDuration::Forever() if the animation + // plays indefinitely. + StickyTimeDuration mEndTime; // Progress towards the end of the current iteration. If the effect is // being sampled backwards, this will go from 1.0 to 0.0. // Will be null if the animation is neither animating nor @@ -172,7 +176,7 @@ class KeyframeEffectReadOnly : public AnimationEffectReadOnly public: KeyframeEffectReadOnly(nsIDocument* aDocument, Element* aTarget, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, const TimingParams& aTiming); NS_DECL_ISUPPORTS_INHERITED @@ -209,7 +213,7 @@ public: // Temporary workaround to return both the target element and pseudo-type // until we implement PseudoElement (bug 1174575). void GetTarget(Element*& aTarget, - nsCSSPseudoElements::Type& aPseudoType) const { + CSSPseudoElementType& aPseudoType) const { aTarget = mTarget; aPseudoType = mPseudoType; } @@ -322,7 +326,7 @@ public: protected: KeyframeEffectReadOnly(nsIDocument* aDocument, Element* aTarget, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, AnimationEffectTimingReadOnly* aTiming); virtual ~KeyframeEffectReadOnly(); @@ -351,7 +355,7 @@ protected: static void BuildAnimationPropertyList( JSContext* aCx, Element* aTarget, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, JS::Handle aFrames, InfallibleTArray& aResult, ErrorResult& aRv); @@ -360,7 +364,7 @@ protected: RefPtr mAnimation; OwningNonNull mTiming; - nsCSSPseudoElements::Type mPseudoType; + CSSPseudoElementType mPseudoType; InfallibleTArray mProperties; @@ -395,7 +399,7 @@ class KeyframeEffect : public KeyframeEffectReadOnly public: KeyframeEffect(nsIDocument* aDocument, Element* aTarget, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, const TimingParams& aTiming); JSObject* WrapObject(JSContext* aCx, diff --git a/dom/animation/PseudoElementHashEntry.h b/dom/animation/PseudoElementHashEntry.h index 84aaf597ffef..c1f90e670cd1 100644 --- a/dom/animation/PseudoElementHashEntry.h +++ b/dom/animation/PseudoElementHashEntry.h @@ -9,18 +9,19 @@ #include "mozilla/dom/Element.h" #include "mozilla/HashFunctions.h" -#include "nsCSSPseudoElements.h" #include "PLDHashTable.h" namespace mozilla { +enum class CSSPseudoElementType : uint8_t; + struct PseudoElementHashKey { dom::Element* mElement; - nsCSSPseudoElements::Type mPseudoType; + CSSPseudoElementType mPseudoType; }; -// A hash entry that uses a RefPtr, nsCSSPseudoElements::Type pair +// A hash entry that uses a RefPtr, CSSPseudoElementType pair class PseudoElementHashEntry : public PLDHashEntryHdr { public: @@ -47,12 +48,14 @@ public: if (!aKey) return 0; - return mozilla::HashGeneric(aKey->mElement, aKey->mPseudoType); + // Convert the scoped enum into an integer while adding it to hash. + return mozilla::HashGeneric(aKey->mElement, + static_cast(aKey->mPseudoType)); } enum { ALLOW_MEMMOVE = true }; RefPtr mElement; - nsCSSPseudoElements::Type mPseudoType; + CSSPseudoElementType mPseudoType; }; } // namespace mozilla diff --git a/dom/animation/test/css-animations/file_animation-computed-timing.html b/dom/animation/test/css-animations/file_animation-computed-timing.html index 6a94b23a4d6d..3fae01c34b7b 100644 --- a/dom/animation/test/css-animations/file_animation-computed-timing.html +++ b/dom/animation/test/css-animations/file_animation-computed-timing.html @@ -188,11 +188,11 @@ test(function(t) { }, 'endTime of an infinitely repeating zero-duration animation'); test(function(t) { - // Fill forwards so div.getAnimations()[0] wouldn't return + // Fill forwards so div.getAnimations()[0] won't return an // undefined value. var div = addDiv(t, {style: 'animation: moveAnimation 10s -100s forwards'}); var effect = div.getAnimations()[0].effect; - assert_equals(effect.getComputedTiming().endTime, 0, + assert_equals(effect.getComputedTiming().endTime, -90000, 'Initial value of endTime'); }, 'endTime of an animation that finishes before its startTime'); diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index b903ace5d6a6..c63df7b4b44a 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -3368,7 +3368,7 @@ void Element::GetAnimationsUnsorted(nsTArray>& aAnimations) { EffectSet* effects = EffectSet::GetEffectSet(this, - nsCSSPseudoElements::ePseudo_NotPseudoElement); + CSSPseudoElementType::NotPseudo); if (!effects) { return; } diff --git a/dom/base/WebSocket.cpp b/dom/base/WebSocket.cpp index 1ae6ebf2f1b5..418afea439fb 100644 --- a/dom/base/WebSocket.cpp +++ b/dom/base/WebSocket.cpp @@ -2523,6 +2523,9 @@ public: bool PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) { + // We don't call WorkerRunnable::PreDispatch because it would assert the + // wrong thing about which thread we're on. + AssertIsOnMainThread(); return true; } @@ -2530,6 +2533,9 @@ public: PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aDispatchResult) { + // We don't call WorkerRunnable::PostDispatch because it would assert the + // wrong thing about which thread we're on. + AssertIsOnMainThread(); } private: @@ -2696,6 +2702,10 @@ public: bool PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) { + // We don't call WorkerRunnable::PreDispatch because it would assert the + // wrong thing about which thread we're on. We're on whichever thread the + // channel implementation is running on (probably the main thread or socket + // transport thread). return true; } @@ -2703,6 +2713,10 @@ public: PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aDispatchResult) { + // We don't call WorkerRunnable::PreDispatch because it would assert the + // wrong thing about which thread we're on. We're on whichever thread the + // channel implementation is running on (probably the main thread or socket + // transport thread). } private: diff --git a/dom/base/nsDOMMutationObserver.cpp b/dom/base/nsDOMMutationObserver.cpp index 095cda319c1d..c809adc9d91b 100644 --- a/dom/base/nsDOMMutationObserver.cpp +++ b/dom/base/nsDOMMutationObserver.cpp @@ -389,7 +389,7 @@ nsAnimationReceiver::RecordAnimationMutation(Animation* aAnimation, } mozilla::dom::Element* animationTarget; - nsCSSPseudoElements::Type pseudoType; + CSSPseudoElementType pseudoType; effect->GetTarget(animationTarget, pseudoType); if (!animationTarget) { return; diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index 06805278f2e4..3bf8fce33c9f 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -101,6 +101,7 @@ #include "nsIDOMStyleSheet.h" #include "nsIStyleSheetService.h" #include "nsContentPermissionHelper.h" +#include "nsCSSPseudoElements.h" // for CSSPseudoElementType #include "nsNetUtil.h" #include "nsDocument.h" #include "HTMLImageElement.h" @@ -2247,13 +2248,12 @@ ComputeAnimationValue(nsCSSProperty aProperty, StyleAnimationValue& aOutput) { - if (!StyleAnimationValue::ComputeValue( - aProperty, - aElement, - nsCSSPseudoElements::ePseudo_NotPseudoElement, - aInput, - false, - aOutput)) { + if (!StyleAnimationValue::ComputeValue(aProperty, + aElement, + CSSPseudoElementType::NotPseudo, + aInput, + false, + aOutput)) { return false; } diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 145f4c31ac1d..f1eb070729d0 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -5002,6 +5002,8 @@ nsGlobalWindow::SetOuterSize(int32_t aLengthCSSPixels, bool aIsWidth, height = lengthDevPixels; } aError = treeOwnerAsWin->SetSize(width, height, true); + + CheckForDPIChange(); } void @@ -5323,6 +5325,8 @@ nsGlobalWindow::SetScreenXOuter(int32_t aScreenX, ErrorResult& aError, bool aCal x = CSSToDevIntPixels(aScreenX); aError = treeOwnerAsWin->SetPosition(x, y); + + CheckForDPIChange(); } void @@ -5383,6 +5387,8 @@ nsGlobalWindow::SetScreenYOuter(int32_t aScreenY, ErrorResult& aError, bool aCal y = CSSToDevIntPixels(aScreenY); aError = treeOwnerAsWin->SetPosition(x, y); + + CheckForDPIChange(); } void @@ -7063,8 +7069,11 @@ nsGlobalWindow::MoveToOuter(int32_t aXPos, int32_t aYPos, ErrorResult& aError, b getter_AddRefs(screen)); } - LayoutDevicePoint devPos; if (screen) { + // On secondary displays, the "CSS px" coordinates are offset so that they + // share their origin with global desktop pixels, to avoid ambiguities in + // the coordinate space when there are displays with different DPIs. + // (See the corresponding code in GetScreenXY() above.) int32_t screenLeftDeskPx, screenTopDeskPx, w, h; screen->GetRectDisplayPix(&screenLeftDeskPx, &screenTopDeskPx, &w, &h); CSSIntPoint cssPos(aXPos - screenLeftDeskPx, aYPos - screenTopDeskPx); @@ -7072,20 +7081,21 @@ nsGlobalWindow::MoveToOuter(int32_t aXPos, int32_t aYPos, ErrorResult& aError, b double scale; screen->GetDefaultCSSScaleFactor(&scale); - devPos = cssPos * CSSToLayoutDeviceScale(scale); + LayoutDevicePoint devPos = cssPos * CSSToLayoutDeviceScale(scale); - int32_t screenLeftDevPx, screenTopDevPx; - screen->GetRect(&screenLeftDevPx, &screenTopDevPx, &w, &h); - devPos.x += screenLeftDevPx; - devPos.y += screenTopDevPx; + screen->GetContentsScaleFactor(&scale); + DesktopPoint deskPos = devPos / DesktopToLayoutDeviceScale(scale); + aError = treeOwnerAsWin->SetPositionDesktopPix(screenLeftDeskPx + deskPos.x, + screenTopDeskPx + deskPos.y); } else { // We couldn't find a screen? Just assume a 1:1 mapping. CSSIntPoint cssPos(aXPos, aXPos); CheckSecurityLeftAndTop(&cssPos.x, &cssPos.y, aCallerIsChrome); - devPos = cssPos * CSSToLayoutDeviceScale(1.0); + LayoutDevicePoint devPos = cssPos * CSSToLayoutDeviceScale(1.0); + aError = treeOwnerAsWin->SetPosition(devPos.x, devPos.y); } - aError = treeOwnerAsWin->SetPosition(devPos.x, devPos.y); + CheckForDPIChange(); } void @@ -7135,6 +7145,8 @@ nsGlobalWindow::MoveByOuter(int32_t aXDif, int32_t aYDif, ErrorResult& aError, b nsIntSize newDevPos(CSSToDevIntPixels(cssPos)); aError = treeOwnerAsWin->SetPosition(newDevPos.width, newDevPos.height); + + CheckForDPIChange(); } void @@ -7193,6 +7205,8 @@ nsGlobalWindow::ResizeToOuter(int32_t aWidth, int32_t aHeight, ErrorResult& aErr nsIntSize devSz(CSSToDevIntPixels(cssSize)); aError = treeOwnerAsWin->SetSize(devSz.width, devSz.height, true); + + CheckForDPIChange(); } void @@ -7262,6 +7276,8 @@ nsGlobalWindow::ResizeByOuter(int32_t aWidthDif, int32_t aHeightDif, nsIntSize newDevSize(CSSToDevIntPixels(cssSize)); aError = treeOwnerAsWin->SetSize(newDevSize.width, newDevSize.height, true); + + CheckForDPIChange(); } void @@ -13958,6 +13974,23 @@ nsGlobalWindow::CreateImageBitmap(const ImageBitmapSource& aImage, return ImageBitmap::Create(this, aImage, Some(gfx::IntRect(aSx, aSy, aSw, aSh)), aRv); } +// Helper called by methods that move/resize the window, +// to ensure the presContext (if any) is aware of resolution +// change that may happen in multi-monitor configuration. +void +nsGlobalWindow::CheckForDPIChange() +{ + if (mDocShell) { + RefPtr presContext; + mDocShell->GetPresContext(getter_AddRefs(presContext)); + if (presContext) { + if (presContext->DeviceContext()->CheckDPIChange()) { + presContext->UIResolutionChanged(); + } + } + } +} + template class nsPIDOMWindow; template class nsPIDOMWindow; template class nsPIDOMWindow; diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index f4ae24cc52fb..0c7848e34a14 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -1652,6 +1652,10 @@ protected: // show, in that case we show a separate dialog to ask this question. bool ConfirmDialogIfNeeded(); + // Helper called after moving/resizing, to update docShell's presContext + // if we have caused a resolution change by moving across monitors. + void CheckForDPIChange(); + private: // Fire the JS engine's onNewGlobalObject hook. Only used on inner windows. void FireOnNewGlobalObject(); diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index 0ab8ab37da7d..9788c6db5245 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -178,6 +178,7 @@ static uint32_t sForgetSkippableBeforeCC = 0; static uint32_t sPreviousSuspectedCount = 0; static uint32_t sCleanupsSinceLastGC = UINT32_MAX; static bool sNeedsFullCC = false; +static bool sNeedsFullGC = false; static bool sNeedsGCAfterCC = false; static bool sIncrementalCC = false; static bool sDidPaintAfterPreviousICCSlice = false; @@ -1312,7 +1313,14 @@ nsJSContext::GarbageCollectNow(JS::gcreason::Reason aReason, } JSGCInvocationKind gckind = aShrinking == ShrinkingGC ? GC_SHRINK : GC_NORMAL; - JS::PrepareForFullGC(sRuntime); + + if (sNeedsFullGC || aReason != JS::gcreason::CC_WAITING) { + sNeedsFullGC = false; + JS::PrepareForFullGC(sRuntime); + } else { + CycleCollectedJSRuntime::Get()->PrepareWaitingZonesForGC(); + } + if (aIncremental == IncrementalGC) { JS::StartIncrementalGC(sRuntime, gckind, aReason, aSliceMillis); } else { @@ -2009,6 +2017,8 @@ nsJSContext::RunNextCollectorTimer() void nsJSContext::PokeGC(JS::gcreason::Reason aReason, int aDelay) { + sNeedsFullGC = sNeedsFullGC || aReason != JS::gcreason::CC_WAITING; + if (sGCTimer || sInterSliceGCTimer || sShuttingDown) { // There's already a timer for GC'ing, just return return; @@ -2278,13 +2288,10 @@ DOMGCSliceCallback(JSRuntime *aRt, JS::GCProgress aProgress, const JS::GCDescrip } } else { nsJSContext::KillFullGCTimer(); + } - // Avoid shrinking during heavy activity, which is suggested by - // compartment GC. We don't need to shrink after a shrinking GC as this - // happens automatically in this case. - if (aDesc.invocationKind_ == GC_NORMAL) { - nsJSContext::PokeShrinkGCBuffers(); - } + if (aDesc.invocationKind_ == GC_NORMAL) { + nsJSContext::PokeShrinkGCBuffers(); } if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) { @@ -2380,6 +2387,7 @@ mozilla::dom::StartupJSEnvironment() sLikelyShortLivingObjectsNeedingGC = 0; sPostGCEventsToConsole = false; sNeedsFullCC = false; + sNeedsFullGC = false; sNeedsGCAfterCC = false; gNameSpaceManager = nullptr; sRuntime = nullptr; diff --git a/dom/base/nsNodeUtils.cpp b/dom/base/nsNodeUtils.cpp index 7a356339c089..0186a3e35d3b 100644 --- a/dom/base/nsNodeUtils.cpp +++ b/dom/base/nsNodeUtils.cpp @@ -6,6 +6,7 @@ #include "nsNodeUtils.h" #include "nsContentUtils.h" +#include "nsCSSPseudoElements.h" #include "nsINode.h" #include "nsIContent.h" #include "mozilla/dom/Element.h" @@ -235,13 +236,13 @@ nsNodeUtils::GetTargetForAnimation(const Animation* aAnimation) } Element* target; - nsCSSPseudoElements::Type pseudoType; + CSSPseudoElementType pseudoType; effect->GetTarget(target, pseudoType); // If the animation targets a pseudo-element, we don't dispatch // notifications for it. (In the future we will have PseudoElement // objects we can use as the target of the notifications.) - if (pseudoType != nsCSSPseudoElements::ePseudo_NotPseudoElement) { + if (pseudoType != CSSPseudoElementType::NotPseudo) { return nullptr; } diff --git a/dom/base/nsOpenURIInFrameParams.cpp b/dom/base/nsOpenURIInFrameParams.cpp index 97706c0edd26..3f26dde20e42 100644 --- a/dom/base/nsOpenURIInFrameParams.cpp +++ b/dom/base/nsOpenURIInFrameParams.cpp @@ -5,11 +5,13 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsOpenURIInFrameParams.h" +#include "mozilla/BasePrincipal.h" NS_IMPL_ISUPPORTS(nsOpenURIInFrameParams, nsIOpenURIInFrameParams) -nsOpenURIInFrameParams::nsOpenURIInFrameParams() : - mIsPrivate(false) +nsOpenURIInFrameParams::nsOpenURIInFrameParams(const mozilla::DocShellOriginAttributes& aOriginAttributes) + : mOpenerOriginAttributes(aOriginAttributes) + , mIsPrivate(false) { } @@ -22,6 +24,7 @@ nsOpenURIInFrameParams::GetReferrer(nsAString& aReferrer) aReferrer = mReferrer; return NS_OK; } + NS_IMETHODIMP nsOpenURIInFrameParams::SetReferrer(const nsAString& aReferrer) { @@ -36,9 +39,19 @@ nsOpenURIInFrameParams::GetIsPrivate(bool* aIsPrivate) *aIsPrivate = mIsPrivate; return NS_OK; } + NS_IMETHODIMP nsOpenURIInFrameParams::SetIsPrivate(bool aIsPrivate) { mIsPrivate = aIsPrivate; return NS_OK; } + +NS_IMETHODIMP +nsOpenURIInFrameParams::GetOpenerOriginAttributes(JSContext* aCx, + JS::MutableHandle aValue) +{ + bool ok = ToJSValue(aCx, mOpenerOriginAttributes, aValue); + NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); + return NS_OK; +} diff --git a/dom/base/nsOpenURIInFrameParams.h b/dom/base/nsOpenURIInFrameParams.h index 3e606fc682b9..7fdd6a4bd85a 100644 --- a/dom/base/nsOpenURIInFrameParams.h +++ b/dom/base/nsOpenURIInFrameParams.h @@ -7,16 +7,22 @@ #include "nsIBrowserDOMWindow.h" #include "nsString.h" +namespace mozilla { +class DocShellOriginAttributes; +} + class nsOpenURIInFrameParams final : public nsIOpenURIInFrameParams { public: NS_DECL_ISUPPORTS NS_DECL_NSIOPENURIINFRAMEPARAMS - nsOpenURIInFrameParams(); + explicit nsOpenURIInFrameParams(const mozilla::DocShellOriginAttributes& aOriginAttributes); private: ~nsOpenURIInFrameParams(); + + mozilla::DocShellOriginAttributes mOpenerOriginAttributes; nsString mReferrer; bool mIsPrivate; }; diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp index f39e0f478c82..4a82e2522113 100644 --- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -70,6 +70,10 @@ #include "WebGLVertexArray.h" #include "WebGLVertexAttribData.h" +#ifdef MOZ_WIDGET_COCOA +#include "nsCocoaFeatures.h" +#endif + // Generated #include "mozilla/dom/WebGLRenderingContextBinding.h" @@ -109,6 +113,7 @@ WebGLContext::WebGLContext() , mNeedsFakeNoAlpha(false) , mNeedsFakeNoDepth(false) , mNeedsFakeNoStencil(false) + , mNeedsEmulatedLoneDepthStencil(false) { mGeneration = 0; mInvalidated = false; @@ -891,6 +896,14 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight) if (!mOptions.stencil && gl->Caps().stencil) mNeedsFakeNoStencil = true; + +#ifdef MOZ_WIDGET_COCOA + if (!nsCocoaFeatures::IsAtLeastVersion(10, 12) && + gl->Vendor() == GLVendor::Intel) + { + mNeedsEmulatedLoneDepthStencil = true; + } +#endif } // Update mOptions. @@ -1847,10 +1860,19 @@ WebGLContext::ScopedMaskWorkaround::~ScopedMaskWorkaround() mWebGL.gl->fEnable(LOCAL_GL_DEPTH_TEST); } if (mFakeNoStencil) { + MOZ_ASSERT(mWebGL.mStencilTestEnabled); mWebGL.gl->fEnable(LOCAL_GL_STENCIL_TEST); } } +/*static*/ bool +WebGLContext::ScopedMaskWorkaround::HasDepthButNoStencil(const WebGLFramebuffer* fb) +{ + const auto& depth = fb->DepthAttachment(); + const auto& stencil = fb->StencilAttachment(); + return depth.IsDefined() && !stencil.IsDefined(); +} + //////////////////////////////////////// ScopedUnpackReset::ScopedUnpackReset(WebGLContext* webgl) diff --git a/dom/canvas/WebGLContext.h b/dom/canvas/WebGLContext.h index 8bc4787e9469..0add07206cb4 100644 --- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -1505,6 +1505,7 @@ protected: bool mNeedsFakeNoAlpha; bool mNeedsFakeNoDepth; bool mNeedsFakeNoStencil; + bool mNeedsEmulatedLoneDepthStencil; struct ScopedMaskWorkaround { WebGLContext& mWebGL; @@ -1527,11 +1528,32 @@ protected: webgl.mDepthTestEnabled; } + static bool HasDepthButNoStencil(const WebGLFramebuffer* fb); + static bool ShouldFakeNoStencil(WebGLContext& webgl) { - // We should only be doing this if we're about to draw to the backbuffer. - return !webgl.mBoundDrawFramebuffer && - webgl.mNeedsFakeNoStencil && - webgl.mStencilTestEnabled; + if (!webgl.mStencilTestEnabled) + return false; + + if (!webgl.mBoundDrawFramebuffer) { + if (webgl.mNeedsFakeNoStencil) + return true; + + if (webgl.mNeedsEmulatedLoneDepthStencil && + webgl.mOptions.depth && !webgl.mOptions.stencil) + { + return true; + } + + return false; + } + + if (webgl.mNeedsEmulatedLoneDepthStencil && + HasDepthButNoStencil(webgl.mBoundDrawFramebuffer)) + { + return true; + } + + return false; } explicit ScopedMaskWorkaround(WebGLContext& webgl); diff --git a/dom/canvas/moz.build b/dom/canvas/moz.build index a157e9d91c88..8597e63df6a2 100644 --- a/dom/canvas/moz.build +++ b/dom/canvas/moz.build @@ -7,7 +7,7 @@ TEST_DIRS += ['compiledtest'] # Number changes to this file to avoid bug 1081323 (clobber after changing a manifest): -# 5 +# 11 MOCHITEST_MANIFESTS += [ 'test/crossorigin/mochitest.ini', diff --git a/dom/canvas/test/webgl-conformance/mochi-single.html b/dom/canvas/test/webgl-conformance/mochi-single.html index 22577c47f1b7..79bf7c6be96a 100644 --- a/dom/canvas/test/webgl-conformance/mochi-single.html +++ b/dom/canvas/test/webgl-conformance/mochi-single.html @@ -117,7 +117,6 @@ function GetExpectedTestFailSet() { failSet['conformance/glsl/functions/glsl-function-sin.html'] = true; failSet['conformance/misc/object-deletion-behaviour.html'] = true; failSet['conformance/textures/tex-image-with-format-and-type.html'] = true; - failSet['conformance/textures/texture-mips.html'] = true; failSet['conformance/textures/texture-npot.html'] = true; failSet['conformance/textures/texture-size-cube-maps.html'] = true; } else if (DriverInfo.getOSVersion() >= OS_VERSION_ANDROID_ICS) { @@ -135,7 +134,6 @@ function GetExpectedTestFailSet() { failSet['conformance/state/gl-get-calls.html'] = true; failSet['conformance/textures/tex-image-with-format-and-type.html'] = true; failSet['conformance/textures/tex-sub-image-2d.html'] = true; - failSet['conformance/textures/texture-mips.html'] = true; failSet['conformance/textures/texture-size-cube-maps.html'] = true; } else { // Android 2.3 slaves. @@ -144,7 +142,6 @@ function GetExpectedTestFailSet() { failSet['conformance/misc/object-deletion-behaviour.html'] = true; failSet['conformance/programs/program-test.html'] = true; failSet['conformance/textures/tex-image-and-sub-image-2d-with-video.html'] = true; - failSet['conformance/textures/texture-mips.html'] = true; failSet['conformance/textures/texture-npot.html'] = true; } break; @@ -158,7 +155,6 @@ function GetExpectedTestFailSet() { failSet['conformance/misc/object-deletion-behaviour.html'] = true; failSet['conformance/programs/get-active-test.html'] = true; failSet['conformance/textures/tex-input-validation.html'] = true; - failSet['conformance/textures/texture-mips.html'] = true; failSet['conformance/textures/texture-npot.html'] = true; failSet['conformance/textures/texture-size-cube-maps.html'] = true; failSet['conformance/textures/texture-size.html'] = true; diff --git a/dom/canvas/test/webgl-mochitest.ini b/dom/canvas/test/webgl-mochitest.ini index 138ee94d6965..9251401ac647 100644 --- a/dom/canvas/test/webgl-mochitest.ini +++ b/dom/canvas/test/webgl-mochitest.ini @@ -15,11 +15,11 @@ fail-if = (os == 'android') [webgl-mochitest/ensure-exts/test_EXT_color_buffer_half_float.html] fail-if = (os == 'android') [webgl-mochitest/ensure-exts/test_EXT_disjoint_timer_query.html] -fail-if = (os == 'android') || (os == 'linux') || (os == 'mac') || (os == 'win') +fail-if = (os == 'android') || (os == 'mac') || (os == 'win') [webgl-mochitest/ensure-exts/test_EXT_frag_depth.html] fail-if = (os == 'android') [webgl-mochitest/ensure-exts/test_EXT_sRGB.html] -fail-if = (os == 'android') || (os == 'linux') || (os == 'mac' && os_version == '10.6') || (os == 'win') +fail-if = (os == 'android') || (os == 'mac' && os_version == '10.6') || (os == 'win') [webgl-mochitest/ensure-exts/test_EXT_shader_texture_lod.html] fail-if = (os == 'android') || (os == 'linux') || (os == 'mac') [webgl-mochitest/ensure-exts/test_EXT_texture_filter_anisotropic.html] @@ -60,6 +60,8 @@ support-files = captureStream_common.js [webgl-mochitest/test_fb_param_crash.html] [webgl-mochitest/test_hidden_alpha.html] skip-if = (os == 'b2g') || buildapp == 'mulet' # Mulet - bug 1093639 (crashes in libLLVM-3.0.so) +[webgl-mochitest/test_hidden_depth_stencil.html] +fail-if = (os == 'win' && (os_version == '5.1' || os_version == '6.1')) [webgl-mochitest/test_implicit_color_buffer_float.html] [webgl-mochitest/test_highp_fs.html] [webgl-mochitest/test_no_arr_points.html] diff --git a/dom/canvas/test/webgl-mochitest/test_hidden_depth_stencil.html b/dom/canvas/test/webgl-mochitest/test_hidden_depth_stencil.html new file mode 100644 index 000000000000..987af9e371e2 --- /dev/null +++ b/dom/canvas/test/webgl-mochitest/test_hidden_depth_stencil.html @@ -0,0 +1,159 @@ + +WebGL test: Hidden depth/stencil passes without a depth/stencil buffer respectively + + + + + + + + + diff --git a/dom/html/HTMLSourceElement.cpp b/dom/html/HTMLSourceElement.cpp index 33c238a28ae3..378c86abf76b 100644 --- a/dom/html/HTMLSourceElement.cpp +++ b/dom/html/HTMLSourceElement.cpp @@ -82,6 +82,20 @@ HTMLSourceElement::WouldMatchMediaForDocument(const nsAString& aMedia, return pctx && mediaList->Matches(pctx, nullptr); } +void +HTMLSourceElement::UpdateMediaList(const nsAttrValue* aValue) +{ + mMediaList = nullptr; + nsString mediaStr; + if (!aValue || (mediaStr = aValue->GetStringValue()).IsEmpty()) { + return; + } + + nsCSSParser cssParser; + mMediaList = new nsMediaList(); + cssParser.ParseMediaList(mediaStr, nullptr, 0, mMediaList, false); +} + nsresult HTMLSourceElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName, const nsAttrValue* aValue, bool aNotify) @@ -105,23 +119,17 @@ HTMLSourceElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName, img->PictureSourceSrcsetChanged(AsContent(), strVal, aNotify); } else if (aName == nsGkAtoms::sizes) { img->PictureSourceSizesChanged(AsContent(), strVal, aNotify); - } else if (aName == nsGkAtoms::media || - aName == nsGkAtoms::type) { + } else if (aName == nsGkAtoms::media) { + UpdateMediaList(aValue); + img->PictureSourceMediaOrTypeChanged(AsContent(), aNotify); + } else if (aName == nsGkAtoms::type) { img->PictureSourceMediaOrTypeChanged(AsContent(), aNotify); } } } } else if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::media) { - mMediaList = nullptr; - if (aValue) { - nsString mediaStr = aValue->GetStringValue(); - if (!mediaStr.IsEmpty()) { - nsCSSParser cssParser; - mMediaList = new nsMediaList(); - cssParser.ParseMediaList(mediaStr, nullptr, 0, mMediaList, false); - } - } + UpdateMediaList(aValue); } else if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::src) { mSrcMediaSource = nullptr; if (aValue) { diff --git a/dom/html/HTMLSourceElement.h b/dom/html/HTMLSourceElement.h index a49685765d04..cce02930ef3f 100644 --- a/dom/html/HTMLSourceElement.h +++ b/dom/html/HTMLSourceElement.h @@ -13,6 +13,7 @@ #include "mozilla/dom/HTMLMediaElement.h" class nsMediaList; +class nsAttrValue; namespace mozilla { namespace dom { @@ -118,6 +119,9 @@ protected: private: RefPtr mMediaList; RefPtr mSrcMediaSource; + + // Generates a new nsMediaList using the given input + void UpdateMediaList(const nsAttrValue* aValue); }; } // namespace dom diff --git a/dom/indexedDB/test/mochitest.ini b/dom/indexedDB/test/mochitest.ini index 48bb8daacb13..21d94ff2f300 100644 --- a/dom/indexedDB/test/mochitest.ini +++ b/dom/indexedDB/test/mochitest.ini @@ -127,8 +127,7 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116 [test_blob_archive.html] skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116 [test_blob_file_backed.html] -# This test can only run in the main process. -skip-if = buildapp == 'b2g' || e10s +skip-if = buildapp == 'b2g' [test_blob_simple.html] skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116 [test_blob_worker_crash.html] diff --git a/dom/indexedDB/test/unit/test_blob_file_backed.js b/dom/indexedDB/test/unit/test_blob_file_backed.js index 327860b92eb4..664c9e2c94c8 100644 --- a/dom/indexedDB/test/unit/test_blob_file_backed.js +++ b/dom/indexedDB/test/unit/test_blob_file_backed.js @@ -9,10 +9,6 @@ var testGenerator = testSteps(); function testSteps() { - const fileIOFlags = 0x02 | // PR_WRONLY - 0x08 | // PR_CREATEFILE - 0x20; // PR_TRUNCATE - const filePerms = 0o664; const fileData = "abcdefghijklmnopqrstuvwxyz"; const fileType = "text/plain"; @@ -23,22 +19,12 @@ function testSteps() info("Creating temp file"); - let dirSvc = - SpecialPowers.Cc["@mozilla.org/file/directory_service;1"] - .getService(SpecialPowers.Ci.nsIProperties); - let testFile = dirSvc.get("ProfD", SpecialPowers.Ci.nsIFile); - testFile.createUnique(SpecialPowers.Ci.nsIFile.NORMAL_FILE_TYPE, filePerms); + SpecialPowers.createFiles([{data:fileData, options:{type:fileType}}], function (files) { + testGenerator.next(files[0]); + }); - info("Writing temp file"); + let file = yield undefined; - let outStream = - SpecialPowers.Cc["@mozilla.org/network/file-output-stream;1"] - .createInstance(SpecialPowers.Ci.nsIFileOutputStream); - outStream.init(testFile, fileIOFlags, filePerms, 0); - outStream.write(fileData, fileData.length); - outStream.close(); - - let file = SpecialPowers.createDOMFile(testFile.path, { type: fileType }); ok(file instanceof File, "Got a File object"); is(file.size, fileData.length, "Correct size"); is(file.type, fileType, "Correct type"); @@ -67,7 +53,6 @@ function testSteps() db = event.target.result; file = null; - testFile.remove(false); objectStore = db.transaction(objectStoreName).objectStore(objectStoreName); objectStore.get(objectStoreKey).onsuccess = grabEventAndContinueHandler; diff --git a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js index a3050b19e424..2fecf818e89b 100644 --- a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js +++ b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js @@ -18,11 +18,11 @@ function is(a, b, msg) { } function ok(cond, msg) { - do_check_true(!!cond, Components.stack.caller); + do_check_true(!!cond, Components.stack.caller); } function isnot(a, b, msg) { - do_check_neq(a, b, Components.stack.caller); + do_check_neq(a, b, Components.stack.caller); } function executeSoon(fun) { @@ -69,6 +69,8 @@ function finishTest() "free"); } + SpecialPowers.removeFiles(); + do_execute_soon(function(){ testGenerator.close(); do_test_finished(); @@ -150,12 +152,12 @@ function compareKeys(k1, k2) { if (!(k2 instanceof Array) || k1.length != k2.length) return false; - + for (let i = 0; i < k1.length; ++i) { if (!compareKeys(k1[i], k2[i])) return false; } - + return true; } @@ -484,7 +486,46 @@ var SpecialPowers = { return Cu; }, - createDOMFile: function(file, options) { - return new File(file, options); + // Based on SpecialPowersObserver.prototype.receiveMessage + createFiles: function(requests, callback) { + let dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties); + let filePaths = new Array; + if (!this._createdFiles) { + this._createdFiles = new Array; + } + let createdFiles = this._createdFiles; + requests.forEach(function(request) { + const filePerms = 0o666; + let testFile = dirSvc.get("ProfD", Ci.nsIFile); + if (request.name) { + testFile.append(request.name); + } else { + testFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, filePerms); + } + let outStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream); + outStream.init(testFile, 0x02 | 0x08 | 0x20, // PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE + filePerms, 0); + if (request.data) { + outStream.write(request.data, request.data.length); + outStream.close(); + } + filePaths.push(new File(testFile.path, request.options)); + createdFiles.push(testFile); + }); + + setTimeout(function () { + callback(filePaths); + }, 0); + }, + + removeFiles: function() { + if (this._createdFiles) { + this._createdFiles.forEach(function (testFile) { + try { + testFile.remove(false); + } catch (e) {} + }); + this._createdFiles = null; + } }, }; diff --git a/dom/interfaces/base/nsIBrowserDOMWindow.idl b/dom/interfaces/base/nsIBrowserDOMWindow.idl index 5515f066d55e..993e6ac0d28f 100644 --- a/dom/interfaces/base/nsIBrowserDOMWindow.idl +++ b/dom/interfaces/base/nsIBrowserDOMWindow.idl @@ -11,11 +11,13 @@ interface nsIURI; interface nsIFrameLoaderOwner; [scriptable, uuid(e774db14-79ac-4156-a7a3-aa3fd0a22c10)] - interface nsIOpenURIInFrameParams : nsISupports { attribute DOMString referrer; attribute boolean isPrivate; + + [implicit_jscontext] + readonly attribute jsval openerOriginAttributes; }; [scriptable, uuid(9d17f3dd-672b-451e-afd2-b1115df780d5)] diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 7caac03fd375..c2e334f1b75f 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -73,6 +73,7 @@ #include "mozilla/unused.h" #include "mozInlineSpellChecker.h" +#include "nsDocShell.h" #include "nsIConsoleListener.h" #include "nsICycleCollectorListener.h" #include "nsIDragService.h" @@ -872,12 +873,22 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener, baseURI->GetSpec(baseURIString); } + auto* opener = nsPIDOMWindowOuter::From(aParent); + nsIDocShell* openerShell; + RefPtr openerDocShell; + if (opener && (openerShell = opener->GetDocShell())) { + openerDocShell = static_cast(openerShell); + } + nsresult rv; if (!SendCreateWindow(aTabOpener, newChild, aChromeFlags, aCalledFromJS, aPositionSpecified, aSizeSpecified, url, name, features, baseURIString, + openerDocShell + ? openerDocShell->GetOriginAttributes() + : DocShellOriginAttributes(), &rv, aWindowIsNew, &frameScripts, diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 82ef86946308..19273a86d192 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -5465,6 +5465,7 @@ ContentParent::RecvCreateWindow(PBrowserParent* aThisTab, const nsString& aName, const nsCString& aFeatures, const nsCString& aBaseURI, + const DocShellOriginAttributes& aOpenerOriginAttributes, nsresult* aResult, bool* aWindowIsNew, InfallibleTArray* aFrameScripts, @@ -5563,7 +5564,8 @@ ContentParent::RecvCreateWindow(PBrowserParent* aThisTab, loadContext->GetUsePrivateBrowsing(&isPrivate); } - nsCOMPtr params = new nsOpenURIInFrameParams(); + nsCOMPtr params = + new nsOpenURIInFrameParams(aOpenerOriginAttributes); params->SetReferrer(NS_ConvertUTF8toUTF16(aBaseURI)); params->SetIsPrivate(isPrivate); diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index bbd791186e13..37b01f180b80 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -501,6 +501,7 @@ public: const nsString& aName, const nsCString& aFeatures, const nsCString& aBaseURI, + const DocShellOriginAttributes& aOpenerOriginAttributes, nsresult* aResult, bool* aWindowIsNew, InfallibleTArray* aFrameScripts, diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index 8a41b8e5ee26..f2257416c90f 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -94,6 +94,7 @@ using mozilla::dom::ContentParentId from "mozilla/dom/ipc/IdType.h"; using struct LookAndFeelInt from "mozilla/widget/WidgetMessageUtils.h"; using class mozilla::dom::ipc::StructuredCloneData from "ipc/IPCMessageUtils.h"; using mozilla::DataStorageType from "ipc/DataStorageIPCUtils.h"; +using mozilla::DocShellOriginAttributes from "mozilla/ipc/BackgroundUtils.h"; union ChromeRegistryItem { @@ -1172,7 +1173,8 @@ parent: nsCString aURI, nsString aName, nsCString aFeatures, - nsCString aBaseURI) + nsCString aBaseURI, + DocShellOriginAttributes aOpenerOriginAttributes) returns (nsresult rv, bool windowOpened, FrameScriptInfo[] frameScripts, diff --git a/dom/media/AudioStream.cpp b/dom/media/AudioStream.cpp index 4290669caaba..a5fc1f6e934b 100644 --- a/dom/media/AudioStream.cpp +++ b/dom/media/AudioStream.cpp @@ -273,6 +273,25 @@ OpenDumpFile(AudioStream* aStream) return f; } +template +typename EnableIf::value, void>::Type +WriteDumpFileHelper(T* aInput, size_t aSamples, FILE* aFile) { + fwrite(aInput, sizeof(T), aSamples, aFile); +} + +template +typename EnableIf::value, void>::Type +WriteDumpFileHelper(T* aInput, size_t aSamples, FILE* aFile) { + AutoTArray buf; + buf.SetLength(aSamples*2); + uint8_t* output = buf.Elements(); + for (uint32_t i = 0; i < aSamples; ++i) { + SetUint16LE(output + i*2, int16_t(aInput[i]*32767.0f)); + } + fwrite(output, 2, aSamples, aFile); + fflush(aFile); +} + static void WriteDumpFile(FILE* aDumpFile, AudioStream* aStream, uint32_t aFrames, void* aBuffer) @@ -281,23 +300,21 @@ WriteDumpFile(FILE* aDumpFile, AudioStream* aStream, uint32_t aFrames, return; uint32_t samples = aStream->GetOutChannels()*aFrames; - if (AUDIO_OUTPUT_FORMAT == AUDIO_FORMAT_S16) { - fwrite(aBuffer, 2, samples, aDumpFile); - return; - } - NS_ASSERTION(AUDIO_OUTPUT_FORMAT == AUDIO_FORMAT_FLOAT32, "bad format"); - AutoTArray buf; - buf.SetLength(samples*2); - float* input = static_cast(aBuffer); - uint8_t* output = buf.Elements(); - for (uint32_t i = 0; i < samples; ++i) { - SetUint16LE(output + i*2, int16_t(input[i]*32767.0f)); - } - fwrite(output, 2, samples, aDumpFile); - fflush(aDumpFile); + using SampleT = AudioSampleTraits::Type; + WriteDumpFileHelper(reinterpret_cast(aBuffer), samples, aDumpFile); } +template +struct ToCubebFormat { + static const cubeb_sample_format value = CUBEB_SAMPLE_FLOAT32NE; +}; + +template <> +struct ToCubebFormat { + static const cubeb_sample_format value = CUBEB_SAMPLE_S16NE; +}; + nsresult AudioStream::Init(uint32_t aNumChannels, uint32_t aRate, const dom::AudioChannel aAudioChannel) @@ -333,12 +350,8 @@ AudioStream::Init(uint32_t aNumChannels, uint32_t aRate, return NS_ERROR_INVALID_ARG; } #endif - if (AUDIO_OUTPUT_FORMAT == AUDIO_FORMAT_S16) { - params.format = CUBEB_SAMPLE_S16NE; - } else { - params.format = CUBEB_SAMPLE_FLOAT32NE; - } + params.format = ToCubebFormat::value; mAudioClock.Init(); return OpenCubeb(params); diff --git a/dom/media/DecoderTraits.cpp b/dom/media/DecoderTraits.cpp index a801fe0818ed..9d43550243bf 100644 --- a/dom/media/DecoderTraits.cpp +++ b/dom/media/DecoderTraits.cpp @@ -134,8 +134,10 @@ static const char* const gWaveTypes[5] = { nullptr }; -static char const *const gWaveCodecs[2] = { +static char const *const gWaveCodecs[4] = { "1", // Microsoft PCM Format + "6", // aLaw Encoding + "7", // uLaw Encoding nullptr }; diff --git a/dom/media/mediasource/TrackBuffersManager.cpp b/dom/media/mediasource/TrackBuffersManager.cpp index 3c9c6c9cc0d2..e2e9e0815381 100644 --- a/dom/media/mediasource/TrackBuffersManager.cpp +++ b/dom/media/mediasource/TrackBuffersManager.cpp @@ -104,7 +104,6 @@ TrackBuffersManager::TrackBuffersManager(dom::SourceBufferAttributes* aAttribute , mEvictionOccurred(false) , mMonitor("TrackBuffersManager") , mAppendRunning(false) - , mSegmentParserLoopRunning(false) { MOZ_ASSERT(NS_IsMainThread(), "Must be instanciated on the main thread"); } @@ -301,7 +300,6 @@ void TrackBuffersManager::CompleteResetParserState() { MOZ_ASSERT(OnTaskQueue()); - MOZ_DIAGNOSTIC_ASSERT(!mSegmentParserLoopRunning); MSE_DEBUG(""); for (auto& track : GetTracksList()) { @@ -437,7 +435,6 @@ bool TrackBuffersManager::CodedFrameRemoval(TimeInterval aInterval) { MOZ_ASSERT(OnTaskQueue()); - MOZ_ASSERT(!mSegmentParserLoopRunning, "Logic error: Append in progress"); MSE_DEBUG("From %.2fs to %.2f", aInterval.mStart.ToSeconds(), aInterval.mEnd.ToSeconds()); @@ -576,8 +573,6 @@ TrackBuffersManager::SegmentParserLoop() { MOZ_ASSERT(OnTaskQueue()); - mSegmentParserLoopRunning = true; - while (true) { // 1. If the input buffer is empty, then jump to the need more data step below. if (!mInputBuffer || mInputBuffer->IsEmpty()) { @@ -702,7 +697,6 @@ TrackBuffersManager::NeedMoreData() MSE_DEBUG(""); RestoreCachedVariables(); mAppendRunning = false; - mSegmentParserLoopRunning = false; { // Wake-up any pending Abort() MonitorAutoLock mon(mMonitor); @@ -716,7 +710,6 @@ TrackBuffersManager::RejectAppend(nsresult aRejectValue, const char* aName) { MSE_DEBUG("rv=%d", aRejectValue); mAppendRunning = false; - mSegmentParserLoopRunning = false; { // Wake-up any pending Abort() MonitorAutoLock mon(mMonitor); diff --git a/dom/media/mediasource/TrackBuffersManager.h b/dom/media/mediasource/TrackBuffersManager.h index f150e0d49819..6188df4d5474 100644 --- a/dom/media/mediasource/TrackBuffersManager.h +++ b/dom/media/mediasource/TrackBuffersManager.h @@ -350,11 +350,8 @@ private: // Monitor to protect following objects accessed across multipple threads. // mMonitor is also notified if the value of mAppendRunning becomes false. mutable Monitor mMonitor; - // Set to true while SegmentParserLoop is running. + // Set to true while a BufferAppend is running or is pending. Atomic mAppendRunning; - // Set to true while SegmentParserLoop is running. - // This is for diagnostic only. Only accessed on the task queue. - bool mSegmentParserLoopRunning; // Stable audio and video track time ranges. media::TimeIntervals mVideoBufferedRanges; media::TimeIntervals mAudioBufferedRanges; diff --git a/dom/media/moz.build b/dom/media/moz.build index cc661e746a6f..33d21433389d 100644 --- a/dom/media/moz.build +++ b/dom/media/moz.build @@ -155,6 +155,11 @@ EXPORTS.mozilla.media.webrtc += [ 'webrtc/WebrtcGlobal.h', ] +if not CONFIG['MOZ_WEBRTC']: + EXPORTS.mtransport += [ + '../../media/mtransport/runnable_utils.h', + ] + IPDL_SOURCES += [ 'webrtc/PWebrtcGlobal.ipdl' ] diff --git a/dom/media/platforms/agnostic/WAVDecoder.cpp b/dom/media/platforms/agnostic/WAVDecoder.cpp index 648e46a15c90..8f3512625e66 100644 --- a/dom/media/platforms/agnostic/WAVDecoder.cpp +++ b/dom/media/platforms/agnostic/WAVDecoder.cpp @@ -12,6 +12,39 @@ using mp4_demuxer::ByteReader; namespace mozilla { +int16_t +DecodeALawSample(uint8_t aValue) +{ + aValue = aValue ^ 0x55; + int8_t sign = (aValue & 0x80) ? -1 : 1; + uint8_t exponent = (aValue & 0x70) >> 4; + uint8_t mantissa = aValue & 0x0F; + int16_t sample = mantissa << 4; + switch (exponent) { + case 0: + sample += 8; + break; + case 1: + sample += 0x108; + break; + default: + sample += 0x108; + sample <<= exponent - 1; + } + return sign * sample; +} + +int16_t +DecodeULawSample(uint8_t aValue) +{ + aValue = aValue ^ 0xFF; + int8_t sign = (aValue & 0x80) ? -1 : 1; + uint8_t exponent = (aValue & 0x70) >> 4; + uint8_t mantissa = aValue & 0x0F; + int16_t sample = (33 + 2 * mantissa) * (2 << (exponent + 1)) - 33; + return sign * sample; +} + WaveDataDecoder::WaveDataDecoder(const AudioInfo& aConfig, FlushableTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback) @@ -69,18 +102,30 @@ WaveDataDecoder::DoDecode(MediaRawData* aSample) auto buffer = MakeUnique(frames * mInfo.mChannels); for (int i = 0; i < frames; ++i) { for (unsigned int j = 0; j < mInfo.mChannels; ++j) { - if (mInfo.mBitDepth == 8) { + if (mInfo.mProfile == 6) { //ALAW Data uint8_t v = aReader.ReadU8(); + int16_t decoded = DecodeALawSample(v); buffer[i * mInfo.mChannels + j] = - UInt8bitToAudioSample(v); - } else if (mInfo.mBitDepth == 16) { - int16_t v = aReader.ReadLE16(); + IntegerToAudioSample(decoded); + } else if (mInfo.mProfile == 7) { //ULAW Data + uint8_t v = aReader.ReadU8(); + int16_t decoded = DecodeULawSample(v); buffer[i * mInfo.mChannels + j] = - IntegerToAudioSample(v); - } else if (mInfo.mBitDepth == 24) { - int32_t v = aReader.ReadLE24(); - buffer[i * mInfo.mChannels + j] = - Int24bitToAudioSample(v); + IntegerToAudioSample(decoded); + } else { //PCM Data + if (mInfo.mBitDepth == 8) { + uint8_t v = aReader.ReadU8(); + buffer[i * mInfo.mChannels + j] = + UInt8bitToAudioSample(v); + } else if (mInfo.mBitDepth == 16) { + int16_t v = aReader.ReadLE16(); + buffer[i * mInfo.mChannels + j] = + IntegerToAudioSample(v); + } else if (mInfo.mBitDepth == 24) { + int32_t v = aReader.ReadLE24(); + buffer[i * mInfo.mChannels + j] = + Int24bitToAudioSample(v); + } } } } @@ -132,6 +177,8 @@ WaveDataDecoder::IsWave(const nsACString& aMimeType) // WAVdemuxer uses "audio/wave; codecs=aNum". return aMimeType.EqualsLiteral("audio/x-wav") || aMimeType.EqualsLiteral("audio/wave; codecs=1") || + aMimeType.EqualsLiteral("audio/wave; codecs=6") || + aMimeType.EqualsLiteral("audio/wave; codecs=7") || aMimeType.EqualsLiteral("audio/wave; codecs=65534"); } diff --git a/dom/media/platforms/android/AndroidDecoderModule.cpp b/dom/media/platforms/android/AndroidDecoderModule.cpp index b3ad89b05a1a..c7a69bbb2e5b 100644 --- a/dom/media/platforms/android/AndroidDecoderModule.cpp +++ b/dom/media/platforms/android/AndroidDecoderModule.cpp @@ -263,6 +263,8 @@ AndroidDecoderModule::SupportsMimeType(const nsACString& aMimeType) const // To avoid this we check for wav types here. if (aMimeType.EqualsLiteral("audio/x-wav") || aMimeType.EqualsLiteral("audio/wave; codecs=1") || + aMimeType.EqualsLiteral("audio/wave; codecs=6") || + aMimeType.EqualsLiteral("audio/wave; codecs=7") || aMimeType.EqualsLiteral("audio/wave; codecs=65534")) { return false; } diff --git a/dom/media/systemservices/CamerasChild.cpp b/dom/media/systemservices/CamerasChild.cpp index eb73b6ee98c6..4d6a54f9d8f4 100644 --- a/dom/media/systemservices/CamerasChild.cpp +++ b/dom/media/systemservices/CamerasChild.cpp @@ -474,13 +474,14 @@ void Shutdown(void) { OffTheBooksMutexAutoLock lock(CamerasSingleton::Mutex()); - if (!CamerasSingleton::Child()) { + CamerasChild* child = CamerasSingleton::Child(); + if (!child) { // We don't want to cause everything to get fired up if we're // really already shut down. LOG(("Shutdown when already shut down")); return; } - GetCamerasChild()->Shutdown(); + child->ShutdownAll(); } class ShutdownRunnable : public nsRunnable { @@ -505,14 +506,22 @@ private: }; void -CamerasChild::Shutdown() +CamerasChild::ShutdownAll() { + // Called with CamerasSingleton::Mutex() held + ShutdownParent(); + ShutdownChild(); +} + +void +CamerasChild::ShutdownParent() +{ + // Called with CamerasSingleton::Mutex() held { MonitorAutoLock monitor(mReplyMonitor); mIPCIsAlive = false; monitor.NotifyAll(); } - if (CamerasSingleton::Thread()) { LOG(("Dispatching actor deletion")); // Delete the parent actor. @@ -524,6 +533,16 @@ CamerasChild::Shutdown() return NS_OK; }); CamerasSingleton::Thread()->Dispatch(deleteRunnable, NS_DISPATCH_NORMAL); + } else { + LOG(("ShutdownParent called without PBackground thread")); + } +} + +void +CamerasChild::ShutdownChild() +{ + // Called with CamerasSingleton::Mutex() held + if (CamerasSingleton::Thread()) { LOG(("PBackground thread exists, dispatching close")); // Dispatch closing the IPC thread back to us when the // BackgroundChild is closed. @@ -607,7 +626,11 @@ CamerasChild::~CamerasChild() { OffTheBooksMutexAutoLock lock(CamerasSingleton::Mutex()); - Shutdown(); + // In normal circumstances we've already shut down and the + // following does nothing. But on fatal IPC errors we will + // get destructed immediately, and should not try to reach + // the parent. + ShutdownChild(); } MOZ_COUNT_DTOR(CamerasChild); diff --git a/dom/media/systemservices/CamerasChild.h b/dom/media/systemservices/CamerasChild.h index b2809f9e98c0..ca51a6014744 100644 --- a/dom/media/systemservices/CamerasChild.h +++ b/dom/media/systemservices/CamerasChild.h @@ -192,13 +192,9 @@ public: const unsigned int device_nameUTF8Length, char* unique_idUTF8, const unsigned int unique_idUTF8Length); - void Shutdown(); + void ShutdownAll(); webrtc::ExternalRenderer* Callback(CaptureEngine aCapEngine, int capture_id); - void AddCallback(const CaptureEngine aCapEngine, const int capture_id, - webrtc::ExternalRenderer* render); - void RemoveCallback(const CaptureEngine aCapEngine, const int capture_id); - private: CamerasChild(); @@ -207,6 +203,11 @@ private: // decidecated Cameras IPC/PBackground thread. bool DispatchToParent(nsIRunnable* aRunnable, MonitorAutoLock& aMonitor); + void AddCallback(const CaptureEngine aCapEngine, const int capture_id, + webrtc::ExternalRenderer* render); + void RemoveCallback(const CaptureEngine aCapEngine, const int capture_id); + void ShutdownParent(); + void ShutdownChild(); nsTArray mCallbacks; // Protects the callback arrays diff --git a/dom/media/test/can_play_type_wave.js b/dom/media/test/can_play_type_wave.js index 14b8d21acaf2..d3ce534f92c5 100644 --- a/dom/media/test/can_play_type_wave.js +++ b/dom/media/test/can_play_type_wave.js @@ -11,6 +11,8 @@ function check_wave(v, enabled) { // Supported Wave codecs check("audio/wave; codecs=1", "probably"); + check("audio/wave; codecs=6", "probably"); + check("audio/wave; codecs=7", "probably"); // "no codecs" should be supported, I guess check("audio/wave; codecs=", "probably"); check("audio/wave; codecs=\"\"", "probably"); diff --git a/dom/media/test/manifest.js b/dom/media/test/manifest.js index a7b26f3184b4..037249328df4 100644 --- a/dom/media/test/manifest.js +++ b/dom/media/test/manifest.js @@ -158,6 +158,10 @@ var gPlayTests = [ { name:"16bit_wave_extrametadata.wav", type:"audio/x-wav", duration:1.108 }, // 24-bit samples { name:"wavedata_s24.wav", type:"audio/x-wav", duration:1.0 }, + // aLaw compressed wave file + { name:"wavedata_alaw.wav", type:"audio/x-wav", duration:1.0 }, + // uLaw compressed wave file + { name:"wavedata_ulaw.wav", type:"audio/x-wav", duration:1.0 }, // Ogg stream without eof marker { name:"bug461281.ogg", type:"application/ogg", duration:2.208 }, diff --git a/dom/media/test/mochitest.ini b/dom/media/test/mochitest.ini index 73731d9fb6ae..9e2e3d1b812e 100644 --- a/dom/media/test/mochitest.ini +++ b/dom/media/test/mochitest.ini @@ -557,12 +557,16 @@ support-files = wave_metadata_unknown_tag.wav^headers^ wave_metadata_utf8.wav wave_metadata_utf8.wav^headers^ + wavedata_alaw.wav + wavedata_alaw.wav^headers^ wavedata_s24.wav wavedata_s24.wav^headers^ wavedata_s16.wav wavedata_s16.wav^headers^ wavedata_u8.wav wavedata_u8.wav^headers^ + wavedata_ulaw.wav + wavedata_ulaw.wav^headers^ [test_access_control.html] skip-if = buildapp == 'b2g' && toolkit != 'gonk' # bug 1082984 diff --git a/dom/media/test/wavedata_alaw.wav b/dom/media/test/wavedata_alaw.wav new file mode 100644 index 000000000000..ef090d16e0f6 Binary files /dev/null and b/dom/media/test/wavedata_alaw.wav differ diff --git a/dom/media/test/wavedata_alaw.wav^headers^ b/dom/media/test/wavedata_alaw.wav^headers^ new file mode 100644 index 000000000000..4030ea1d3ddb --- /dev/null +++ b/dom/media/test/wavedata_alaw.wav^headers^ @@ -0,0 +1 @@ +Cache-Control: no-store diff --git a/dom/media/test/wavedata_ulaw.wav b/dom/media/test/wavedata_ulaw.wav new file mode 100644 index 000000000000..0874face21b2 Binary files /dev/null and b/dom/media/test/wavedata_ulaw.wav differ diff --git a/dom/media/test/wavedata_ulaw.wav^headers^ b/dom/media/test/wavedata_ulaw.wav^headers^ new file mode 100644 index 000000000000..4030ea1d3ddb --- /dev/null +++ b/dom/media/test/wavedata_ulaw.wav^headers^ @@ -0,0 +1 @@ +Cache-Control: no-store diff --git a/dom/media/tests/mochitest/test_peerConnection_simulcastOffer.html b/dom/media/tests/mochitest/test_peerConnection_simulcastOffer.html index efbfb36d4ccc..dd783b6ff601 100644 --- a/dom/media/tests/mochitest/test_peerConnection_simulcastOffer.html +++ b/dom/media/tests/mochitest/test_peerConnection_simulcastOffer.html @@ -74,15 +74,6 @@ ]); test.chain.insertBefore('PC_LOCAL_CREATE_OFFER', [ - // addTrack will not finish until GMP is initted, but addTrack doesn't - // give us a promise to wait on or a callback. We cannot do - // setParameters until addTrack is finished. So, we create a dummy - // offer, which _does_ give us a promise to wait on, and once that is - // done we know that addTrack is done too. - // TODO(bug 1241153): Remove the need for this hack. - function PC_LOCAL_CREATE_OFFER(test) { - return test.createOffer(test.pcLocal); - }, function PC_LOCAL_SET_RIDS(test) { var senders = test.pcLocal._pc.getSenders(); is(senders.length, 1, "We have exactly one RTP sender"); diff --git a/dom/media/wave/WaveDecoder.cpp b/dom/media/wave/WaveDecoder.cpp index 70ab22c285a1..1962825a6718 100644 --- a/dom/media/wave/WaveDecoder.cpp +++ b/dom/media/wave/WaveDecoder.cpp @@ -52,7 +52,10 @@ WaveDecoder::CanHandleMediaType(const nsACString& aType, { if (aType.EqualsASCII("audio/wave") || aType.EqualsASCII("audio/x-wav") || aType.EqualsASCII("audio/wav") || aType.EqualsASCII("audio/x-pn-wav")) { - return IsEnabled() && (aCodecs.IsEmpty() || aCodecs.EqualsASCII("1")); + return IsEnabled() && (aCodecs.IsEmpty() || + aCodecs.EqualsASCII("1") || + aCodecs.EqualsASCII("6") || + aCodecs.EqualsASCII("7")); } return false; diff --git a/dom/media/webrtc/MediaEngineGonkVideoSource.cpp b/dom/media/webrtc/MediaEngineGonkVideoSource.cpp index 5e1c8696a6b2..4e1eaa3bf5d2 100644 --- a/dom/media/webrtc/MediaEngineGonkVideoSource.cpp +++ b/dom/media/webrtc/MediaEngineGonkVideoSource.cpp @@ -148,7 +148,8 @@ MediaEngineGonkVideoSource::NumCapabilities() nsresult MediaEngineGonkVideoSource::Allocate(const dom::MediaTrackConstraints& aConstraints, const MediaEnginePrefs& aPrefs, - const nsString& aDeviceId) + const nsString& aDeviceId, + const nsACString& aOrigin) { LOG((__FUNCTION__)); diff --git a/dom/media/webrtc/MediaEngineGonkVideoSource.h b/dom/media/webrtc/MediaEngineGonkVideoSource.h index 203e6d82e1eb..0aad56745cf4 100644 --- a/dom/media/webrtc/MediaEngineGonkVideoSource.h +++ b/dom/media/webrtc/MediaEngineGonkVideoSource.h @@ -62,7 +62,8 @@ public: nsresult Allocate(const dom::MediaTrackConstraints &aConstraints, const MediaEnginePrefs &aPrefs, - const nsString& aDeviceId) override; + const nsString& aDeviceId, + const nsACString& aOrigin) override; nsresult Deallocate() override; nsresult Start(SourceMediaStream* aStream, TrackID aID) override; nsresult Stop(SourceMediaStream* aSource, TrackID aID) override; diff --git a/dom/media/webspeech/synth/moz.build b/dom/media/webspeech/synth/moz.build index de03c2fc4a4a..4a2eae08e783 100644 --- a/dom/media/webspeech/synth/moz.build +++ b/dom/media/webspeech/synth/moz.build @@ -41,8 +41,6 @@ if CONFIG['MOZ_WEBSPEECH']: 'test/nsFakeSynthServices.cpp' ] - DIRS = [] - if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': DIRS += ['windows'] diff --git a/dom/notification/Notification.cpp b/dom/notification/Notification.cpp index e68e510c7af4..b81b387aa0f1 100644 --- a/dom/notification/Notification.cpp +++ b/dom/notification/Notification.cpp @@ -375,6 +375,9 @@ protected: bool PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override { + // We don't call WorkerRunnable::PreDispatch because it would assert the + // wrong thing about which thread we're on. + AssertIsOnMainThread(); return true; } @@ -382,6 +385,9 @@ protected: PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override { + // We don't call WorkerRunnable::PostDispatch because it would assert the + // wrong thing about which thread we're on. + AssertIsOnMainThread(); } bool diff --git a/dom/security/test/mixedcontentblocker/test_frameNavigation.html b/dom/security/test/mixedcontentblocker/test_frameNavigation.html index 3ee7b3876515..5b3ae50b0761 100644 --- a/dom/security/test/mixedcontentblocker/test_frameNavigation.html +++ b/dom/security/test/mixedcontentblocker/test_frameNavigation.html @@ -90,12 +90,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=840388 switch(event.data.test) { case "insecurePage_navigate_child": - ok((event.data.msg == "navigated to insecure iframe on insecure page"), "navigating to insecure iframe blocked on insecure page"); + is(event.data.msg, "navigated to insecure iframe on insecure page", "navigating to insecure iframe blocked on insecure page"); testsToRunInsecure["insecurePage_navigate_child"] = true; break; case "insecurePage_navigate_grandchild": - ok((event.data.msg == "navigated to insecure grandchild iframe on insecure page"), "navigating to insecure grandchild iframe blocked on insecure page"); + is(event.data.msg, "navigated to insecure grandchild iframe on insecure page", "navigating to insecure grandchild iframe blocked on insecure page"); testsToRunInsecure["insecurePage_navigate_grandchild"] = true; break; @@ -105,7 +105,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=840388 break; case "blankTarget": - ok((event.data.msg == "opened an http link with target=_blank from a secure page"), "couldn't open an http link in a new window from a secure page"); + is(event.data.msg, "opened an http link with target=_blank from a secure page", "couldn't open an http link in a new window from a secure page"); testsToRunSecure["blankTarget"] = true; break; diff --git a/dom/smil/nsSMILCSSValueType.cpp b/dom/smil/nsSMILCSSValueType.cpp index 7cc2adf9533d..60871ea08e06 100644 --- a/dom/smil/nsSMILCSSValueType.cpp +++ b/dom/smil/nsSMILCSSValueType.cpp @@ -360,14 +360,13 @@ ValueFromStringHelper(nsCSSProperty aPropID, } } nsDependentSubstring subString(aString, subStringBegin); - if (!StyleAnimationValue::ComputeValue( - aPropID, - aTargetElement, - nsCSSPseudoElements::ePseudo_NotPseudoElement, - subString, - true, - aStyleAnimValue, - aIsContextSensitive)) { + if (!StyleAnimationValue::ComputeValue(aPropID, + aTargetElement, + CSSPseudoElementType::NotPseudo, + subString, + true, + aStyleAnimValue, + aIsContextSensitive)) { return false; } if (isNegative) { diff --git a/dom/tests/mochitest/bugs/mochitest.ini b/dom/tests/mochitest/bugs/mochitest.ini index 059788ef4fd9..ac4b17ae2b96 100644 --- a/dom/tests/mochitest/bugs/mochitest.ini +++ b/dom/tests/mochitest/bugs/mochitest.ini @@ -168,4 +168,5 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e1 skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s [test_bug1022869.html] [test_bug1112040.html] +[test_bug1160342_marquee.html] [test_bug1171215.html] diff --git a/dom/tests/mochitest/bugs/test_bug1160342_marquee.html b/dom/tests/mochitest/bugs/test_bug1160342_marquee.html new file mode 100644 index 000000000000..760d98b0b59c --- /dev/null +++ b/dom/tests/mochitest/bugs/test_bug1160342_marquee.html @@ -0,0 +1,228 @@ + + + + + Test for Bug 411103 + + + + +Mozilla Bug 1160342 +

+
+marquee +
+ +
+
+
+ + diff --git a/dom/tests/mochitest/general/test_picture_mutations.html b/dom/tests/mochitest/general/test_picture_mutations.html index bdfd9f7db54c..752b02fa7b34 100644 --- a/dom/tests/mochitest/general/test_picture_mutations.html +++ b/dom/tests/mochitest/general/test_picture_mutations.html @@ -165,7 +165,6 @@ expectEvents(1, 0, function() { is(img.currentSrc, testPNG50, "Should have switched to testPNG50"); -Math.sin(90); // Now add a source *also* wanting that DPI *just before* the // selected source. Properly re-running the algorithm should @@ -231,7 +230,7 @@ Math.sin(90); is(img.currentSrc, testPNG100, "Should still have testPNG100"); // And a valid MQ - source1.media = "(min-resolution: 3dppx)"; + source1.media = "(min-resolution: 1dppx)"; expectEvents(1, 0, function() { // And a valid type... source1.type = "image/png"; diff --git a/dom/workers/ServiceWorkerPrivate.cpp b/dom/workers/ServiceWorkerPrivate.cpp index 54a169bac801..578c985903c5 100644 --- a/dom/workers/ServiceWorkerPrivate.cpp +++ b/dom/workers/ServiceWorkerPrivate.cpp @@ -319,6 +319,8 @@ public: nsCOMPtr runnable = new RegistrationUpdateRunnable(mRegistration, true /* time check */); NS_DispatchToMainThread(runnable.forget()); + + ExtendableEventWorkerRunnable::PostRun(aCx, aWorkerPrivate, aRunResult); } }; diff --git a/dom/workers/ServiceWorkerRegistrar.cpp b/dom/workers/ServiceWorkerRegistrar.cpp index 93b71214928c..cfa9a5cf22f8 100644 --- a/dom/workers/ServiceWorkerRegistrar.cpp +++ b/dom/workers/ServiceWorkerRegistrar.cpp @@ -182,6 +182,7 @@ ServiceWorkerRegistrar::RegisterServiceWorker( bool found = false; for (uint32_t i = 0, len = mData.Length(); i < len; ++i) { if (Equivalent(aData, mData[i])) { + mData[i] = aData; found = true; break; } diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index 848de8e9c805..151c52706941 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -610,9 +610,7 @@ private: WorkerRunnable::PostRun(aCx, aWorkerPrivate, aRunResult); // Match the busy count increase from NotifyRunnable. - if (!aWorkerPrivate->ModifyBusyCountFromWorker(aCx, false)) { - JS_ReportPendingException(aCx); - } + aWorkerPrivate->ModifyBusyCountFromWorker(aCx, false); aWorkerPrivate->CloseHandlerFinished(); } diff --git a/dom/workers/WorkerRunnable.cpp b/dom/workers/WorkerRunnable.cpp index c2fdaf5a8f3e..952a4d83f891 100644 --- a/dom/workers/WorkerRunnable.cpp +++ b/dom/workers/WorkerRunnable.cpp @@ -223,9 +223,7 @@ WorkerRunnable::PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, #endif if (mBehavior == WorkerThreadModifyBusyCount) { - if (!aWorkerPrivate->ModifyBusyCountFromWorker(aCx, false)) { - aRunResult = false; - } + aWorkerPrivate->ModifyBusyCountFromWorker(aCx, false); } if (!aRunResult) { @@ -350,10 +348,44 @@ WorkerRunnable::Run() cx = jsapi.cx(); } - // If we're not on the worker thread we'll either be in our parent's - // compartment or the null compartment, so we need to enter our own. + // Note that we can't assert anything about mWorkerPrivate->GetWrapper() + // existing, since it may in fact have been GCed (and we may be one of the + // runnables cleaning up the worker as a result). + + // If we are on the parent thread and that thread is not the main thread, + // then we must be a dedicated worker (because there are no + // Shared/ServiceWorkers whose parent is itself a worker) and then we + // definitely have a globalObject. If it _is_ the main thread, globalObject + // can be null for workers started from JSMs or other non-window contexts, + // sadly. + MOZ_ASSERT_IF(!targetIsWorkerThread && !isMainThread, + mWorkerPrivate->IsDedicatedWorker() && globalObject); + + // If we're on the parent thread we might be in a null compartment in the + // situation described above when globalObject is null. Make sure to enter + // the compartment of the worker's reflector if there is one. There might + // not be one if we're just starting to compile the script for this worker. Maybe ac; if (!targetIsWorkerThread && mWorkerPrivate->GetWrapper()) { + // If we're on the parent thread and have a reflector and a globalObject, + // then the compartments of cx, globalObject, and the worker's reflector + // should all match. + MOZ_ASSERT_IF(globalObject, + js::GetObjectCompartment(mWorkerPrivate->GetWrapper()) == + js::GetContextCompartment(cx)); + MOZ_ASSERT_IF(globalObject, + js::GetObjectCompartment(mWorkerPrivate->GetWrapper()) == + js::GetObjectCompartment(globalObject->GetGlobalJSObject())); + + // If we're on the parent thread and have a reflector, then our + // JSContext had better be either in the null compartment (and hence + // have no globalObject) or in the compartment of our reflector. + MOZ_ASSERT(!js::GetContextCompartment(cx) || + js::GetObjectCompartment(mWorkerPrivate->GetWrapper()) == + js::GetContextCompartment(cx), + "Must either be in the null compartment or in our reflector " + "compartment"); + ac.emplace(cx, mWorkerPrivate->GetWrapper()); } @@ -610,6 +642,9 @@ bool WorkerSameThreadRunnable::PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) { + // We don't call WorkerRunnable::PreDispatch, because we're using + // WorkerThreadModifyBusyCount for mBehavior, and WorkerRunnable will assert + // that PreDispatch is on the parent thread in that case. aWorkerPrivate->AssertIsOnWorkerThread(); return true; } @@ -619,6 +654,9 @@ WorkerSameThreadRunnable::PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aDispatchResult) { + // We don't call WorkerRunnable::PostDispatch, because we're using + // WorkerThreadModifyBusyCount for mBehavior, and WorkerRunnable will assert + // that PostDispatch is on the parent thread in that case. aWorkerPrivate->AssertIsOnWorkerThread(); if (aDispatchResult) { DebugOnly willIncrement = aWorkerPrivate->ModifyBusyCountFromWorker(aCx, true); @@ -627,21 +665,3 @@ WorkerSameThreadRunnable::PostDispatch(JSContext* aCx, MOZ_ASSERT(willIncrement); } } - -void -WorkerSameThreadRunnable::PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, - bool aRunResult) -{ - MOZ_ASSERT(aCx); - MOZ_ASSERT(aWorkerPrivate); - - aWorkerPrivate->AssertIsOnWorkerThread(); - - DebugOnly willDecrement = aWorkerPrivate->ModifyBusyCountFromWorker(aCx, false); - MOZ_ASSERT(willDecrement); - - if (!aRunResult) { - JS_ReportPendingException(aCx); - } -} - diff --git a/dom/workers/WorkerRunnable.h b/dom/workers/WorkerRunnable.h index d56c9a23a09c..62bfb7a051f5 100644 --- a/dom/workers/WorkerRunnable.h +++ b/dom/workers/WorkerRunnable.h @@ -115,26 +115,45 @@ protected: // By default asserts that Dispatch() is being called on the right thread // (ParentThread if |mTarget| is WorkerThread, or WorkerThread otherwise). // Also increments the busy count of |mWorkerPrivate| if targeting the - // WorkerThread. + // WorkerThread. The JSContext passed in here is the one that was passed to + // Dispatch(). virtual bool PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate); // By default asserts that Dispatch() is being called on the right thread // (ParentThread if |mTarget| is WorkerThread, or WorkerThread otherwise). - // Also reports any Dispatch() failures as an exception on |aCx|, and - // busy count if targeting the WorkerThread and Dispatch() failed. + // Also reports any Dispatch() failures as an exception on |aCx|, and busy + // count if targeting the WorkerThread and Dispatch() failed. The JSContext + // passed in here is the one that was passed to Dispatch(). virtual void PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aDispatchResult); - // Must be implemented by subclasses. Called on the target thread. + // Must be implemented by subclasses. Called on the target thread. The return + // value will be passed to PostRun(). The JSContext passed in here comes from + // an AutoJSAPI (or AutoEntryScript) that we set up on the stack. If + // mBehavior is ParentThreadUnchangedBusyCount, it is in the compartment of + // mWorkerPrivate's reflector (i.e. the worker object in the parent thread), + // unless that reflector is null, in which case it's in the compartment of the + // parent global (which is the compartment reflector would have been in), or + // in the null compartment if there is no parent global. For other mBehavior + // values, we're running on the worker thread and aCx is in whatever + // compartment GetCurrentThreadJSContext() was in when nsIRunnable::Run() got + // called (XXXbz: Why is this a sane thing to be doing now that we have + // multiple globals per worker???). If it wasn't in a compartment, aCx will + // be in either the debugger global's compartment or the worker's global's + // compartment depending on whether IsDebuggerRunnable() is true. virtual bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) = 0; // By default asserts that Run() (and WorkerRun()) were called on the correct - // thread. Any failures (false return from WorkerRun) are reported on |aCx|. - // Also sends an asynchronous message to the ParentThread if the busy - // count was previously modified in PreDispatch(). + // thread. Also sends an asynchronous message to the ParentThread if the + // busy count was previously modified in PreDispatch(). + // + // The aCx passed here is the same one as was passed to WorkerRun and is + // still in the same compartment. If aRunResult is false, any failures on + // aCx are reported. Otherwise failures are left to linger on the JSContext + // and maim later code (XXXbz: Aiming to fix that in bug 1072144). virtual void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult); @@ -386,9 +405,8 @@ protected: PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override; - virtual void - PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, - bool aRunResult) override; + // We just delegate PostRun to WorkerRunnable, since it does exactly + // what we want. }; // Base class for the runnable objects, which makes a synchronous call to diff --git a/dom/workers/Workers.h b/dom/workers/Workers.h index 38125fcd4924..8238a3b300ed 100644 --- a/dom/workers/Workers.h +++ b/dom/workers/Workers.h @@ -294,6 +294,8 @@ SuspendWorkersForWindow(nsPIDOMWindowInner* aWindow); void ResumeWorkersForWindow(nsPIDOMWindowInner* aWindow); +// A class that can be used with WorkerCrossThreadDispatcher to run a +// bit of C++ code on the worker thread. class WorkerTask { protected: @@ -306,6 +308,8 @@ protected: public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WorkerTask) + // The return value here has the same semantics as the return value + // of WorkerRunnable::WorkerRun. virtual bool RunTask(JSContext* aCx) = 0; }; diff --git a/embedding/browser/nsDocShellTreeOwner.cpp b/embedding/browser/nsDocShellTreeOwner.cpp index eb040ee8cc1c..dfe990e498f4 100644 --- a/embedding/browser/nsDocShellTreeOwner.cpp +++ b/embedding/browser/nsDocShellTreeOwner.cpp @@ -570,6 +570,15 @@ nsDocShellTreeOwner::GetDevicePixelsPerDesktopPixel(double* aScale) return NS_OK; } +NS_IMETHODIMP +nsDocShellTreeOwner::SetPositionDesktopPix(int32_t aX, int32_t aY) +{ + // Added to nsIBaseWindow in bug 1247335; + // implement if a use-case is found. + NS_ASSERTION(false, "implement me!"); + return NS_ERROR_NOT_IMPLEMENTED; +} + NS_IMETHODIMP nsDocShellTreeOwner::SetPosition(int32_t aX, int32_t aY) { diff --git a/embedding/browser/nsWebBrowser.cpp b/embedding/browser/nsWebBrowser.cpp index 601e26b38ef3..d656503d394b 100644 --- a/embedding/browser/nsWebBrowser.cpp +++ b/embedding/browser/nsWebBrowser.cpp @@ -1302,6 +1302,15 @@ nsWebBrowser::GetDevicePixelsPerDesktopPixel(double* aScale) return NS_OK; } +NS_IMETHODIMP +nsWebBrowser::SetPositionDesktopPix(int32_t aX, int32_t aY) +{ + // Added to nsIBaseWindow in bug 1247335; + // implement if a use-case is found. + NS_ASSERTION(false, "implement me!"); + return NS_ERROR_NOT_IMPLEMENTED; +} + NS_IMETHODIMP nsWebBrowser::SetPosition(int32_t aX, int32_t aY) { diff --git a/gfx/2d/DrawTargetSkia.cpp b/gfx/2d/DrawTargetSkia.cpp index 2b94f7449b8f..b5ae360d8e40 100644 --- a/gfx/2d/DrawTargetSkia.cpp +++ b/gfx/2d/DrawTargetSkia.cpp @@ -554,6 +554,8 @@ DrawTargetSkia::ShouldLCDRenderText(FontType aFontType, AntialiasMode aAntialias if (aAntialiasMode == AntialiasMode::DEFAULT) { switch (aFontType) { case FontType::MAC: + case FontType::GDI: + case FontType::DWRITE: return true; default: // TODO: Figure out what to do for the other platforms. diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp index 06d4d4fccfa8..2fc629466b60 100644 --- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -31,7 +31,6 @@ #include "TextureGarbageBin.h" #include "gfx2DGlue.h" #include "gfxPrefs.h" -#include "DriverCrashGuard.h" #include "mozilla/IntegerPrintfMacros.h" #include "OGLShaderProgram.h" // for ShaderProgramType @@ -476,11 +475,6 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl) return true; } - GLContextCrashGuard crashGuard; - if (crashGuard.Crashed()) { - return false; - } - mWorkAroundDriverBugs = gfxPrefs::WorkAroundDriverBugs(); SymLoadStruct symbols[] = { diff --git a/gfx/layers/Layers.cpp b/gfx/layers/Layers.cpp index 040c683e0909..15c29d9392a1 100644 --- a/gfx/layers/Layers.cpp +++ b/gfx/layers/Layers.cpp @@ -1117,7 +1117,8 @@ ContainerLayer::ContainerLayer(LayerManager* aManager, void* aImplData) mMayHaveReadbackChild(false), mChildrenChanged(false), mEventRegionsOverride(EventRegionsOverride::NoOverride), - mVRDeviceID(0) + mVRDeviceID(0), + mInputFrameID(0) { MOZ_COUNT_CTOR(ContainerLayer); mContentFlags = 0; // Clear NO_TEXT, NO_TEXT_OVER_TRANSPARENT @@ -1279,7 +1280,8 @@ ContainerLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs) mInheritedXScale, mInheritedYScale, mPresShellResolution, mScaleToResolution, mEventRegionsOverride, - mVRDeviceID); + mVRDeviceID, + mInputFrameID); } bool @@ -2146,7 +2148,7 @@ ContainerLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix) aStream << " [force-ehr]"; } if (mVRDeviceID) { - aStream << nsPrintfCString(" [hmd=%lu]", mVRDeviceID).get(); + aStream << nsPrintfCString(" [hmd=%lu] [hmdframe=%l]", mVRDeviceID, mInputFrameID).get(); } } diff --git a/gfx/layers/Layers.h b/gfx/layers/Layers.h index 27edef846da6..b2d317fb7ca0 100644 --- a/gfx/layers/Layers.h +++ b/gfx/layers/Layers.h @@ -2143,10 +2143,18 @@ public: */ void SetVRDeviceID(uint32_t aVRDeviceID) { mVRDeviceID = aVRDeviceID; + Mutated(); } uint32_t GetVRDeviceID() { return mVRDeviceID; } + void SetInputFrameID(int32_t aInputFrameID) { + mInputFrameID = aInputFrameID; + Mutated(); + } + int32_t GetInputFrameID() { + return mInputFrameID; + } /** * Replace the current effective transform with the given one, @@ -2223,6 +2231,7 @@ protected: bool mChildrenChanged; EventRegionsOverride mEventRegionsOverride; uint32_t mVRDeviceID; + int32_t mInputFrameID; }; /** diff --git a/gfx/layers/basic/BasicCompositor.cpp b/gfx/layers/basic/BasicCompositor.cpp index 3259fda31018..241dfb4e143a 100644 --- a/gfx/layers/basic/BasicCompositor.cpp +++ b/gfx/layers/basic/BasicCompositor.cpp @@ -153,6 +153,32 @@ BasicCompositor::CreateRenderTargetFromSource(const IntRect &aRect, return nullptr; } +already_AddRefed +BasicCompositor::CreateRenderTargetForWindow(const IntRect& aRect, SurfaceInitMode aInit, BufferMode aBufferMode) +{ + if (aBufferMode != BufferMode::BUFFER_NONE) { + return CreateRenderTarget(aRect, aInit); + } + + MOZ_ASSERT(aRect.width != 0 && aRect.height != 0, "Trying to create a render target of invalid size"); + + if (aRect.width * aRect.height == 0) { + return nullptr; + } + + MOZ_ASSERT(mDrawTarget); + + // Adjust bounds rect to account for new origin at (0, 0). + IntRect rect(0, 0, aRect.XMost(), aRect.YMost()); + RefPtr rt = new BasicCompositingRenderTarget(mDrawTarget, rect); + + if (aInit == INIT_MODE_CLEAR) { + mDrawTarget->ClearRect(gfx::Rect(aRect)); + } + + return rt.forget(); +} + already_AddRefed BasicCompositor::CreateDataTextureSource(TextureFlags aFlags) { @@ -557,13 +583,14 @@ BasicCompositor::BeginFrame(const nsIntRegion& aInvalidRegion, *aRenderBoundsOut = Rect(); } + BufferMode bufferMode = BufferMode::BUFFERED; if (mTarget) { // If we have a copy target, then we don't have a widget-provided mDrawTarget (currently). Use a dummy // placeholder so that CreateRenderTarget() works. mDrawTarget = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget(); } else { // StartRemoteDrawingInRegion can mutate mInvalidRegion. - mDrawTarget = mWidget->StartRemoteDrawingInRegion(mInvalidRegion); + mDrawTarget = mWidget->StartRemoteDrawingInRegion(mInvalidRegion, &bufferMode); if (!mDrawTarget) { return; } @@ -581,7 +608,7 @@ BasicCompositor::BeginFrame(const nsIntRegion& aInvalidRegion, // Setup an intermediate render target to buffer all compositing. We will // copy this into mDrawTarget (the widget), and/or mTarget in EndFrame() RefPtr target = - CreateRenderTarget(mInvalidRect.ToUnknownRect(), INIT_MODE_CLEAR); + CreateRenderTargetForWindow(mInvalidRect.ToUnknownRect(), INIT_MODE_CLEAR, bufferMode); if (!target) { if (!mTarget) { mWidget->EndRemoteDrawingInRegion(mDrawTarget, mInvalidRegion); @@ -592,8 +619,7 @@ BasicCompositor::BeginFrame(const nsIntRegion& aInvalidRegion, // We only allocate a surface sized to the invalidated region, so we need to // translate future coordinates. - mRenderTarget->mDrawTarget->SetTransform(Matrix::Translation(-mInvalidRect.x, - -mInvalidRect.y)); + mRenderTarget->mDrawTarget->SetTransform(Matrix::Translation(-mRenderTarget->GetOrigin())); gfxUtils::ClipToRegion(mRenderTarget->mDrawTarget, mInvalidRegion.ToUnknownRegion()); @@ -631,22 +657,25 @@ BasicCompositor::EndFrame() // Pop aInvalidregion mRenderTarget->mDrawTarget->PopClip(); - // Note: Most platforms require us to buffer drawing to the widget surface. - // That's why we don't draw to mDrawTarget directly. - RefPtr source = mRenderTarget->mDrawTarget->Snapshot(); - RefPtr dest(mTarget ? mTarget : mDrawTarget); + if (mTarget || mRenderTarget->mDrawTarget != mDrawTarget) { + // Note: Most platforms require us to buffer drawing to the widget surface. + // That's why we don't draw to mDrawTarget directly. + RefPtr source = mRenderTarget->mDrawTarget->Snapshot(); + RefPtr dest(mTarget ? mTarget : mDrawTarget); - nsIntPoint offset = mTarget ? mTargetBounds.TopLeft() : nsIntPoint(); + nsIntPoint offset = mTarget ? mTargetBounds.TopLeft() : nsIntPoint(); - // The source DrawTarget is clipped to the invalidation region, so we have - // to copy the individual rectangles in the region or else we'll draw blank - // pixels. - for (auto iter = mInvalidRegion.RectIter(); !iter.Done(); iter.Next()) { - const LayoutDeviceIntRect& r = iter.Get(); - dest->CopySurface(source, - IntRect(r.x - mInvalidRect.x, r.y - mInvalidRect.y, r.width, r.height), - IntPoint(r.x - offset.x, r.y - offset.y)); + // The source DrawTarget is clipped to the invalidation region, so we have + // to copy the individual rectangles in the region or else we'll draw blank + // pixels. + for (auto iter = mInvalidRegion.RectIter(); !iter.Done(); iter.Next()) { + const LayoutDeviceIntRect& r = iter.Get(); + dest->CopySurface(source, + IntRect(r.x, r.y, r.width, r.height) - mRenderTarget->GetOrigin(), + IntPoint(r.x, r.y) - offset); + } } + if (!mTarget) { mWidget->EndRemoteDrawingInRegion(mDrawTarget, mInvalidRegion); } diff --git a/gfx/layers/basic/BasicCompositor.h b/gfx/layers/basic/BasicCompositor.h index dfc7d8491fca..fcb7e680403b 100644 --- a/gfx/layers/basic/BasicCompositor.h +++ b/gfx/layers/basic/BasicCompositor.h @@ -62,6 +62,11 @@ public: const CompositingRenderTarget *aSource, const gfx::IntPoint &aSourcePoint) override; + virtual already_AddRefed + CreateRenderTargetForWindow(const gfx::IntRect& aRect, + SurfaceInitMode aInit, + BufferMode aBufferMode); + virtual already_AddRefed CreateDataTextureSource(TextureFlags aFlags = TextureFlags::NO_FLAGS) override; diff --git a/gfx/layers/client/CanvasClient.cpp b/gfx/layers/client/CanvasClient.cpp index 2a5c991c457f..a11c8c35f4ab 100644 --- a/gfx/layers/client/CanvasClient.cpp +++ b/gfx/layers/client/CanvasClient.cpp @@ -25,6 +25,7 @@ #include "nsDebug.h" // for printf_stderr, NS_ASSERTION #include "nsXULAppAPI.h" // for XRE_GetProcessType, etc #include "TextureClientSharedSurface.h" +#include "VRManagerChild.h" using namespace mozilla::gfx; using namespace mozilla::gl; @@ -125,6 +126,7 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) t->mTextureClient = mBuffer; t->mPictureRect = nsIntRect(nsIntPoint(0, 0), mBuffer->GetSize()); t->mFrameID = mFrameID; + t->mInputFrameID = VRManagerChild::Get()->GetInputFrameID(); GetForwarder()->UseTextures(this, textures); mBuffer->SyncWithObject(GetForwarder()->GetSyncObject()); } @@ -481,6 +483,11 @@ CanvasClientSharedSurface::Updated() t->mTextureClient = mFront; t->mPictureRect = nsIntRect(nsIntPoint(0, 0), mFront->GetSize()); t->mFrameID = mFrameID; + // XXX TODO - This reference to VRManagerChild will be moved with the + // implementation of the WebVR 1.0 API, which will enable + // the inputFrameID to be passed through Javascript with + // the new VRDisplay API. + t->mInputFrameID = VRManagerChild::Get()->GetInputFrameID(); forwarder->UseTextures(this, textures); } diff --git a/gfx/layers/composite/CompositableHost.h b/gfx/layers/composite/CompositableHost.h index d34a8b4648b7..a45f62167608 100644 --- a/gfx/layers/composite/CompositableHost.h +++ b/gfx/layers/composite/CompositableHost.h @@ -194,6 +194,7 @@ public: gfx::IntRect mPictureRect; int32_t mFrameID; int32_t mProducerID; + int32_t mInputFrameID; }; virtual void UseTextureHost(const nsTArray& aTextures); virtual void UseComponentAlphaTextures(TextureHost* aTextureOnBlack, @@ -235,6 +236,8 @@ public: return nullptr; } + virtual int32_t GetLastInputFrameID() const { return -1; } + protected: TextureInfo mTextureInfo; uint64_t mAsyncID; diff --git a/gfx/layers/composite/ContainerLayerComposite.cpp b/gfx/layers/composite/ContainerLayerComposite.cpp index 49a73b7560b0..28eb0db4a8d8 100755 --- a/gfx/layers/composite/ContainerLayerComposite.cpp +++ b/gfx/layers/composite/ContainerLayerComposite.cpp @@ -139,8 +139,11 @@ template void ContainerRenderVR(ContainerT* aContainer, LayerManagerComposite* aManager, const gfx::IntRect& aClipRect, - RefPtr aHMD) + RefPtr aHMD, + int32_t aInputFrameID) { + int32_t inputFrameID = -1; + RefPtr surface; Compositor* compositor = aManager->GetCompositor(); @@ -265,6 +268,14 @@ ContainerRenderVR(ContainerT* aContainer, surfaceRect.width, surfaceRect.height)); layerToRender->RenderLayer(surfaceRect); + CompositableHost *ch = layerToRender->GetCompositableHost(); + if (ch) { + int32_t compositableInputFrameID = ch->GetLastInputFrameID(); + if (compositableInputFrameID != -1) { + inputFrameID = compositableInputFrameID; + } + } + if (restoreTransform) { layer->ReplaceEffectiveTransform(childTransform); } @@ -282,7 +293,7 @@ ContainerRenderVR(ContainerT* aContainer, compositor->SetRenderTarget(previousTarget); if (vrRendering) { - vrRendering->SubmitFrame(aContainer->mVRRenderTargetSet); + vrRendering->SubmitFrame(aContainer->mVRRenderTargetSet, inputFrameID); DUMP("<<< ContainerRenderVR [used vrRendering] [%p]\n", aContainer); if (!gfxPrefs::VRMirrorTextures()) { return; @@ -696,7 +707,7 @@ ContainerRender(ContainerT* aContainer, RefPtr hmdInfo = gfx::VRManager::Get()->GetDevice(aContainer->GetVRDeviceID()); if (hmdInfo && hmdInfo->GetConfiguration().IsValid()) { - ContainerRenderVR(aContainer, aManager, aClipRect, hmdInfo); + ContainerRenderVR(aContainer, aManager, aClipRect, hmdInfo, aContainer->GetInputFrameID()); aContainer->mPrepared = nullptr; return; } diff --git a/gfx/layers/composite/ImageHost.cpp b/gfx/layers/composite/ImageHost.cpp index 22b37cbbab74..418bdd8cc792 100644 --- a/gfx/layers/composite/ImageHost.cpp +++ b/gfx/layers/composite/ImageHost.cpp @@ -32,6 +32,7 @@ ImageHost::ImageHost(const TextureInfo& aTextureInfo) , mImageContainer(nullptr) , mLastFrameID(-1) , mLastProducerID(-1) + , mLastInputFrameID(-1) , mBias(BIAS_NONE) , mLocked(false) {} @@ -84,6 +85,7 @@ ImageHost::UseTextureHost(const nsTArray& aTextures) img.mPictureRect = t.mPictureRect; img.mFrameID = t.mFrameID; img.mProducerID = t.mProducerID; + img.mInputFrameID = t.mInputFrameID; } // Recycle any leftover mTextureSources and call PrepareTextureSource on all // images. @@ -357,6 +359,7 @@ ImageHost::Composite(LayerComposite* aLayer, } mLastFrameID = img->mFrameID; mLastProducerID = img->mProducerID; + mLastInputFrameID = img->mInputFrameID; } aEffectChain.mPrimaryEffect = effect; gfx::Rect pictureRect(0, 0, img->mPictureRect.width, img->mPictureRect.height); diff --git a/gfx/layers/composite/ImageHost.h b/gfx/layers/composite/ImageHost.h index c654018cd02f..ebde4cbc3f2f 100644 --- a/gfx/layers/composite/ImageHost.h +++ b/gfx/layers/composite/ImageHost.h @@ -100,6 +100,7 @@ public: int32_t GetLastFrameID() const { return mLastFrameID; } int32_t GetLastProducerID() const { return mLastProducerID; } + virtual int32_t GetLastInputFrameID() const override { return mLastInputFrameID; } enum Bias { // Don't apply bias to frame times @@ -118,6 +119,7 @@ protected: gfx::IntRect mPictureRect; int32_t mFrameID; int32_t mProducerID; + int32_t mInputFrameID; }; /** @@ -135,6 +137,7 @@ protected: ImageContainerParent* mImageContainer; int32_t mLastFrameID; int32_t mLastProducerID; + int32_t mLastInputFrameID; /** * Bias to apply to the next frame. */ diff --git a/gfx/layers/composite/LayerManagerComposite.cpp b/gfx/layers/composite/LayerManagerComposite.cpp index b3eb72d38084..10a8b738c0b4 100644 --- a/gfx/layers/composite/LayerManagerComposite.cpp +++ b/gfx/layers/composite/LayerManagerComposite.cpp @@ -217,14 +217,54 @@ IntersectMaybeRects(const Maybe& aRect1, const Maybe& aRect2 return aRect2; } +/** + * Get accumulated transform of from the context creating layer to the + * given layer. + */ +static Matrix4x4 +GetAccTransformIn3DContext(Layer* aLayer) { + Matrix4x4 transform = aLayer->GetLocalTransform(); + for (Layer* layer = aLayer->GetParent(); + layer && layer->Extend3DContext(); + layer = layer->GetParent()) { + transform = transform * layer->GetLocalTransform(); + } + return transform; +} + void LayerManagerComposite::PostProcessLayers(Layer* aLayer, nsIntRegion& aOpaqueRegion, LayerIntRegion& aVisibleRegion, const Maybe& aClipFromAncestors) { + if (aLayer->Extend3DContext()) { + // For layers participating 3D rendering context, their visible + // region should be empty (invisible), so we pass through them + // without doing anything. + + // Direct children of the establisher may have a clip, becaue the + // item containing it; ex. of nsHTMLScrollFrame, may give it one. + Maybe layerClip = + aLayer->AsLayerComposite()->GetShadowClipRect(); + Maybe ancestorClipForChildren = + IntersectMaybeRects(layerClip, aClipFromAncestors); + MOZ_ASSERT(!layerClip || !aLayer->Combines3DTransformWithAncestors(), + "Only direct children of the establisher could have a clip"); + + for (Layer* child = aLayer->GetLastChild(); + child; + child = child->GetPrevSibling()) { + PostProcessLayers(child, aOpaqueRegion, aVisibleRegion, + ancestorClipForChildren); + } + return; + } + nsIntRegion localOpaque; - Matrix4x4 transform = aLayer->GetLocalTransform(); + // Treat layers on the path to the root of the 3D rendering context as + // a giant layer if it is a leaf. + Matrix4x4 transform = GetAccTransformIn3DContext(aLayer); Matrix transform2d; Maybe integerTranslation; // If aLayer has a simple transform (only an integer translation) then we @@ -242,6 +282,9 @@ LayerManagerComposite::PostProcessLayers(Layer* aLayer, // from our ancestors. LayerComposite* composite = aLayer->AsLayerComposite(); Maybe layerClip = composite->GetShadowClipRect(); + MOZ_ASSERT(!layerClip || !aLayer->Combines3DTransformWithAncestors(), + "The layer with a clip should not participate " + "a 3D rendering context"); Maybe outsideClip = IntersectMaybeRects(layerClip, aClipFromAncestors); diff --git a/gfx/layers/ipc/CompositableForwarder.h b/gfx/layers/ipc/CompositableForwarder.h index ce6f91948c30..f4fef20987b8 100644 --- a/gfx/layers/ipc/CompositableForwarder.h +++ b/gfx/layers/ipc/CompositableForwarder.h @@ -113,13 +113,14 @@ public: struct TimedTextureClient { TimedTextureClient() - : mTextureClient(nullptr), mFrameID(0), mProducerID(0) {} + : mTextureClient(nullptr), mFrameID(0), mProducerID(0), mInputFrameID(0) {} TextureClient* mTextureClient; TimeStamp mTimeStamp; nsIntRect mPictureRect; int32_t mFrameID; int32_t mProducerID; + int32_t mInputFrameID; }; /** * Tell the CompositableHost on the compositor side what textures to use for diff --git a/gfx/layers/ipc/CompositableTransactionParent.cpp b/gfx/layers/ipc/CompositableTransactionParent.cpp index 82327c8bee87..ff5f887e339a 100644 --- a/gfx/layers/ipc/CompositableTransactionParent.cpp +++ b/gfx/layers/ipc/CompositableTransactionParent.cpp @@ -182,6 +182,7 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation t->mPictureRect = timedTexture.picture(); t->mFrameID = timedTexture.frameID(); t->mProducerID = timedTexture.producerID(); + t->mInputFrameID = timedTexture.inputFrameID(); MOZ_ASSERT(ValidatePictureRect(t->mTexture->GetSize(), t->mPictureRect)); MaybeFence maybeFence = timedTexture.fence(); diff --git a/gfx/layers/ipc/CompositorChild.cpp b/gfx/layers/ipc/CompositorChild.cpp index f1600052ab0d..742a3d5faf43 100644 --- a/gfx/layers/ipc/CompositorChild.cpp +++ b/gfx/layers/ipc/CompositorChild.cpp @@ -450,7 +450,8 @@ CompositorChild::SharedFrameMetricsData::SharedFrameMetricsData( , mLayersId(aLayersId) , mAPZCId(aAPZCId) { - mBuffer = new ipc::SharedMemoryBasic(metrics); + mBuffer = new ipc::SharedMemoryBasic; + mBuffer->SetHandle(metrics); mBuffer->Map(sizeof(FrameMetrics)); mMutex = new CrossProcessMutex(handle); MOZ_COUNT_CTOR(SharedFrameMetricsData); diff --git a/gfx/layers/ipc/ImageBridgeChild.cpp b/gfx/layers/ipc/ImageBridgeChild.cpp index 46b3d8336f2d..7b730f56dc4d 100644 --- a/gfx/layers/ipc/ImageBridgeChild.cpp +++ b/gfx/layers/ipc/ImageBridgeChild.cpp @@ -191,7 +191,7 @@ ImageBridgeChild::UseTextures(CompositableClient* aCompositable, textures.AppendElement(TimedTexture(nullptr, t.mTextureClient->GetIPDLActor(), fence.IsValid() ? MaybeFence(fence) : MaybeFence(null_t()), t.mTimeStamp, t.mPictureRect, - t.mFrameID, t.mProducerID)); + t.mFrameID, t.mProducerID, t.mInputFrameID)); } mTxn->AddNoSwapEdit(OpUseTexture(nullptr, aCompositable->GetIPDLActor(), textures)); diff --git a/gfx/layers/ipc/LayerTransactionParent.cpp b/gfx/layers/ipc/LayerTransactionParent.cpp index 01a35553bf94..0cadf2d24c2f 100644 --- a/gfx/layers/ipc/LayerTransactionParent.cpp +++ b/gfx/layers/ipc/LayerTransactionParent.cpp @@ -414,6 +414,7 @@ LayerTransactionParent::RecvUpdate(InfallibleTArray&& cset, containerLayer->SetScaleToResolution(attrs.scaleToResolution(), attrs.presShellResolution()); containerLayer->SetEventRegionsOverride(attrs.eventRegionsOverride()); + containerLayer->SetInputFrameID(attrs.inputFrameID()); if (attrs.hmdDeviceID()) { containerLayer->SetVRDeviceID(attrs.hmdDeviceID()); diff --git a/gfx/layers/ipc/LayersMessages.ipdlh b/gfx/layers/ipc/LayersMessages.ipdlh index 796426a67cc3..410dd96863d5 100644 --- a/gfx/layers/ipc/LayersMessages.ipdlh +++ b/gfx/layers/ipc/LayersMessages.ipdlh @@ -252,6 +252,7 @@ struct ContainerLayerAttributes { bool scaleToResolution; EventRegionsOverride eventRegionsOverride; uint32_t hmdDeviceID; + int32_t inputFrameID; }; struct ColorLayerAttributes { LayerColor color; IntRect bounds; }; struct CanvasLayerAttributes { Filter filter; IntRect bounds; }; @@ -396,6 +397,7 @@ struct TimedTexture { IntRect picture; uint32_t frameID; uint32_t producerID; + int32_t inputFrameID; }; /** diff --git a/gfx/layers/ipc/ShadowLayers.cpp b/gfx/layers/ipc/ShadowLayers.cpp index 343dddb37099..459edc61b37b 100644 --- a/gfx/layers/ipc/ShadowLayers.cpp +++ b/gfx/layers/ipc/ShadowLayers.cpp @@ -396,7 +396,7 @@ ShadowLayerForwarder::UseTextures(CompositableClient* aCompositable, textures.AppendElement(TimedTexture(nullptr, t.mTextureClient->GetIPDLActor(), fence.IsValid() ? MaybeFence(fence) : MaybeFence(null_t()), t.mTimeStamp, t.mPictureRect, - t.mFrameID, t.mProducerID)); + t.mFrameID, t.mProducerID, t.mInputFrameID)); if ((t.mTextureClient->GetFlags() & TextureFlags::IMMEDIATE_UPLOAD) && t.mTextureClient->HasInternalBuffer()) { diff --git a/gfx/layers/opengl/GrallocTextureClient.cpp b/gfx/layers/opengl/GrallocTextureClient.cpp index 44f5b34e63b7..fbb7ba7c4eb0 100644 --- a/gfx/layers/opengl/GrallocTextureClient.cpp +++ b/gfx/layers/opengl/GrallocTextureClient.cpp @@ -12,6 +12,7 @@ #include "mozilla/layers/ISurfaceAllocator.h" #include "mozilla/layers/ShadowLayerUtilsGralloc.h" #include "gfx2DGlue.h" +#include "gfxPrefs.h" // for gfxPrefs #include "SharedSurfaceGralloc.h" #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 diff --git a/gfx/src/DriverCrashGuard.cpp b/gfx/src/DriverCrashGuard.cpp index 34aa39fa1720..4edbe127ab43 100644 --- a/gfx/src/DriverCrashGuard.cpp +++ b/gfx/src/DriverCrashGuard.cpp @@ -525,13 +525,13 @@ GLContextCrashGuard::UpdateEnvironment() void GLContextCrashGuard::LogCrashRecovery() { - gfxCriticalNote << "GLContext just crashed and is now disabled."; + gfxCriticalNote << "GLContext just crashed."; } void GLContextCrashGuard::LogFeatureDisabled() { - gfxCriticalNote << "GLContext is disabled due to a previous crash."; + gfxCriticalNote << "GLContext remains enabled despite a previous crash."; } } // namespace gfx diff --git a/gfx/tests/gtest/TestGfxPrefs.cpp b/gfx/tests/gtest/TestGfxPrefs.cpp index 2d602c1b2ffb..72b698ed61db 100644 --- a/gfx/tests/gtest/TestGfxPrefs.cpp +++ b/gfx/tests/gtest/TestGfxPrefs.cpp @@ -79,3 +79,28 @@ TEST(GfxPrefs, Set) { gfxPrefs::SetAPZMaxVelocity(-1.0f); ASSERT_TRUE(gfxPrefs::APZMaxVelocity() == -1.0f); } + +#ifdef MOZ_CRASHREPORTER +// Randomly test the function we use in nsExceptionHandler.cpp here: +extern bool SimpleNoCLibDtoA(double aValue, char* aBuffer, int aBufferLength); +TEST(GfxPrefs, StringUtility) +{ + char testBuffer[64]; + double testVal[] = {13.4, + 3324243.42, + 0.332424342, + 864.0, + 86400 * 100000000.0 * 10000000000.0 * 10000000000.0 * 100.0, + 86400.0 * 366.0 * 100.0 + 14243.44332}; + for (size_t i=0; i(blurDataSize); if (!mData) { return nullptr; } - memset(mData, 0, blurDataSize); + memset(mData.get(), 0, blurDataSize); RefPtr dt = - gfxPlatform::GetPlatform()->CreateDrawTargetForData(mData, size, + gfxPlatform::GetPlatform()->CreateDrawTargetForData(mData.get(), size, mBlur->GetStride(), SurfaceFormat::A8); if (!dt) { @@ -119,11 +120,11 @@ DrawBlur(gfxContext* aDestinationCtx, already_AddRefed gfxAlphaBoxBlur::DoBlur(DrawTarget* aDT, IntPoint* aTopLeft) { - mBlur->Blur(mData); + mBlur->Blur(mData.get()); *aTopLeft = mBlur->GetRect().TopLeft(); - return aDT->CreateSourceSurfaceFromData(mData, + return aDT->CreateSourceSurfaceFromData(mData.get(), mBlur->GetSize(), mBlur->GetStride(), SurfaceFormat::A8); diff --git a/gfx/thebes/gfxBlur.h b/gfx/thebes/gfxBlur.h index 2210949b6749..d76c7236bfaf 100644 --- a/gfx/thebes/gfxBlur.h +++ b/gfx/thebes/gfxBlur.h @@ -188,7 +188,7 @@ protected: /** * The temporary alpha surface. */ - nsAutoArrayPtr mData; + mozilla::UniquePtr mData; /** * The object that actually does the blurring for us. diff --git a/gfx/vr/gfxVR.h b/gfx/vr/gfxVR.h index ca111cb941f5..55c1890c85d9 100644 --- a/gfx/vr/gfxVR.h +++ b/gfx/vr/gfxVR.h @@ -161,6 +161,7 @@ struct VRDeviceInfo struct VRHMDSensorState { double timestamp; + int32_t inputFrameID; VRStateValidFlags flags; float orientation[4]; float position[3]; @@ -244,7 +245,7 @@ public: virtual already_AddRefed CreateRenderTargetSet(layers::Compositor *aCompositor, const IntSize& aSize) = 0; virtual void DestroyRenderTargetSet(RenderTargetSet *aRTSet) = 0; - virtual void SubmitFrame(RenderTargetSet *aRTSet) = 0; + virtual void SubmitFrame(RenderTargetSet *aRTSet, int32_t aInputFrameID) = 0; protected: VRHMDRenderingSupport() { } }; diff --git a/gfx/vr/gfxVROculus.cpp b/gfx/vr/gfxVROculus.cpp index e41b7d3441d5..87cbfd512c4d 100644 --- a/gfx/vr/gfxVROculus.cpp +++ b/gfx/vr/gfxVROculus.cpp @@ -246,6 +246,7 @@ FromFovPort(const ovrFovPort& aFOV) HMDInfoOculus::HMDInfoOculus(ovrSession aSession) : VRHMDInfo(VRHMDType::Oculus, false) , mSession(aSession) + , mInputFrameID(0) { MOZ_ASSERT(sizeof(HMDInfoOculus::DistortionVertex) == sizeof(VRDistortionVertex), "HMDInfoOculus::DistortionVertex must match the size of VRDistortionVertex"); @@ -345,7 +346,7 @@ HMDInfoOculus::KeepSensorTracking() void HMDInfoOculus::NotifyVsync(const mozilla::TimeStamp& aVsyncTimestamp) { - + ++mInputFrameID; } void @@ -518,7 +519,7 @@ HMDInfoOculus::DestroyRenderTargetSet(RenderTargetSet *aRTSet) } void -HMDInfoOculus::SubmitFrame(RenderTargetSet *aRTSet) +HMDInfoOculus::SubmitFrame(RenderTargetSet *aRTSet, int32_t aInputFrameID) { RenderTargetSetOculus *rts = static_cast(aRTSet); MOZ_ASSERT(rts->hmd != nullptr); @@ -547,7 +548,7 @@ HMDInfoOculus::SubmitFrame(RenderTargetSet *aRTSet) do_CalcEyePoses(rts->hmd->mLastTrackingState.HeadPose.ThePose, hmdToEyeViewOffset, layer.RenderPose); ovrLayerHeader *layers = &layer.Header; - ovrResult orv = ovr_SubmitFrame(mSession, 0, nullptr, &layers, 1); + ovrResult orv = ovr_SubmitFrame(mSession, aInputFrameID, nullptr, &layers, 1); //printf_stderr("Submitted frame %d, result: %d\n", rts->textureSet->CurrentIndex, orv); if (orv != ovrSuccess) { // not visible? failed? diff --git a/gfx/vr/gfxVROculus.h b/gfx/vr/gfxVROculus.h index 8177b001b3dc..cf47660c1511 100644 --- a/gfx/vr/gfxVROculus.h +++ b/gfx/vr/gfxVROculus.h @@ -45,7 +45,7 @@ public: /* VRHMDRenderingSupport */ already_AddRefed CreateRenderTargetSet(layers::Compositor *aCompositor, const IntSize& aSize) override; void DestroyRenderTargetSet(RenderTargetSet *aRTSet) override; - void SubmitFrame(RenderTargetSet *aRTSet) override; + void SubmitFrame(RenderTargetSet *aRTSet, int32_t aInputFrameID) override; ovrSession GetOculusSession() const { return mSession; } @@ -68,6 +68,7 @@ protected: ovrHmdDesc mDesc; ovrFovPort mFOVPort[2]; ovrTrackingState mLastTrackingState; + int mInputFrameID; }; } // namespace impl diff --git a/gfx/vr/ipc/VRManagerChild.cpp b/gfx/vr/ipc/VRManagerChild.cpp index 0663839f54e2..1aba97532b26 100644 --- a/gfx/vr/ipc/VRManagerChild.cpp +++ b/gfx/vr/ipc/VRManagerChild.cpp @@ -24,6 +24,7 @@ void ReleaseVRManagerParentSingleton() { } VRManagerChild::VRManagerChild() + : mInputFrameID(-1) { MOZ_COUNT_CTOR(VRManagerChild); MOZ_ASSERT(NS_IsMainThread()); @@ -157,6 +158,7 @@ VRManagerChild::RecvUpdateDeviceSensors(nsTArray&& aDeviceSensor for (auto& device: mDevices) { if (device->GetDeviceInfo().GetDeviceID() == sensorUpdate.mDeviceID) { device->UpdateSensorState(sensorUpdate.mSensorState); + mInputFrameID = sensorUpdate.mSensorState.inputFrameID; break; } } @@ -182,5 +184,11 @@ VRManagerChild::RefreshVRDevicesWithCallback(dom::Navigator* aNavigator) return success; } +int +VRManagerChild::GetInputFrameID() +{ + return mInputFrameID; +} + } // namespace gfx } // namespace mozilla diff --git a/gfx/vr/ipc/VRManagerChild.h b/gfx/vr/ipc/VRManagerChild.h index 293f7d783b0a..345349d2b68f 100644 --- a/gfx/vr/ipc/VRManagerChild.h +++ b/gfx/vr/ipc/VRManagerChild.h @@ -25,6 +25,7 @@ class VRManagerChild : public PVRManagerChild public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(VRManagerChild) + int GetInputFrameID(); bool GetVRDevices(nsTArray >& aDevices); bool RefreshVRDevicesWithCallback(dom::Navigator* aNavigator); static VRManagerChild* StartUpInChildProcess(Transport* aTransport, @@ -52,6 +53,7 @@ private: nsTArray > mDevices; nsTArray mNavigatorCallbacks; + int32_t mInputFrameID; }; } // namespace mozilla diff --git a/gfx/vr/ipc/VRMessageUtils.h b/gfx/vr/ipc/VRMessageUtils.h index 1c17f1eb61f0..1a5e8004dd3f 100644 --- a/gfx/vr/ipc/VRMessageUtils.h +++ b/gfx/vr/ipc/VRMessageUtils.h @@ -127,6 +127,7 @@ struct ParamTraits static void Write(Message* aMsg, const paramType& aParam) { WriteParam(aMsg, aParam.timestamp); + WriteParam(aMsg, aParam.inputFrameID); WriteParam(aMsg, aParam.flags); WriteParam(aMsg, aParam.orientation[0]); WriteParam(aMsg, aParam.orientation[1]); @@ -152,6 +153,7 @@ struct ParamTraits static bool Read(const Message* aMsg, void** aIter, paramType* aResult) { if (!ReadParam(aMsg, aIter, &(aResult->timestamp)) || + !ReadParam(aMsg, aIter, &(aResult->inputFrameID)) || !ReadParam(aMsg, aIter, &(aResult->flags)) || !ReadParam(aMsg, aIter, &(aResult->orientation[0])) || !ReadParam(aMsg, aIter, &(aResult->orientation[1])) || diff --git a/ipc/chromium/src/base/shared_memory.h b/ipc/chromium/src/base/shared_memory.h index a1b6d927139a..49291cd601c3 100644 --- a/ipc/chromium/src/base/shared_memory.h +++ b/ipc/chromium/src/base/shared_memory.h @@ -43,17 +43,18 @@ class SharedMemory { // Create a new SharedMemory object from an existing, open // shared memory file. - SharedMemory(SharedMemoryHandle handle, bool read_only); - - // Create a new SharedMemory object from an existing, open - // shared memory file that was created by a remote process and not shared - // to the current process. - SharedMemory(SharedMemoryHandle handle, bool read_only, - base::ProcessHandle process); + SharedMemory(SharedMemoryHandle init_handle, bool read_only) + : SharedMemory() { + SetHandle(init_handle, read_only); + } // Destructor. Will close any open files. ~SharedMemory(); + // Initialize a new SharedMemory object from an existing, open + // shared memory file. + bool SetHandle(SharedMemoryHandle handle, bool read_only); + // Return true iff the given handle is valid (i.e. not the distingished // invalid value; NULL for a HANDLE and -1 for a file descriptor) static bool IsHandleValid(const SharedMemoryHandle& handle); @@ -116,7 +117,7 @@ class SharedMemory { // Closes the open shared memory segment. // It is safe to call Close repeatedly. - void Close(); + void Close(bool unmap_view = true); // Share the shared memory to another process. Attempts // to create a platform-specific new_handle which can be diff --git a/ipc/chromium/src/base/shared_memory_posix.cc b/ipc/chromium/src/base/shared_memory_posix.cc index dc8732017374..bc8238555bd1 100644 --- a/ipc/chromium/src/base/shared_memory_posix.cc +++ b/ipc/chromium/src/base/shared_memory_posix.cc @@ -26,35 +26,24 @@ SharedMemory::SharedMemory() max_size_(0) { } -SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only) - : mapped_file_(handle.fd), - inode_(0), - memory_(NULL), - read_only_(read_only), - max_size_(0) { - struct stat st; - if (fstat(handle.fd, &st) == 0) { - // If fstat fails, then the file descriptor is invalid and we'll learn this - // fact when Map() fails. - inode_ = st.st_ino; - } -} - -SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only, - ProcessHandle process) - : mapped_file_(handle.fd), - memory_(NULL), - read_only_(read_only), - max_size_(0) { - // We don't handle this case yet (note the ignored parameter); let's die if - // someone comes calling. - NOTREACHED(); -} - SharedMemory::~SharedMemory() { Close(); } +bool SharedMemory::SetHandle(SharedMemoryHandle handle, bool read_only) { + DCHECK(mapped_file_ == -1); + + struct stat st; + if (fstat(handle.fd, &st) < 0) { + return false; + } + + mapped_file_ = handle.fd; + inode_ = st.st_ino; + read_only_ = read_only; + return true; +} + // static bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) { return handle.fd >= 0; @@ -268,10 +257,12 @@ bool SharedMemory::ShareToProcessCommon(ProcessId processId, } -void SharedMemory::Close() { - Unmap(); +void SharedMemory::Close(bool unmap_view) { + if (unmap_view) { + Unmap(); + } - if (mapped_file_ > 0) { + if (mapped_file_ >= 0) { close(mapped_file_); mapped_file_ = -1; } diff --git a/ipc/chromium/src/base/shared_memory_win.cc b/ipc/chromium/src/base/shared_memory_win.cc index 02d90bd2a51d..757443a718fa 100644 --- a/ipc/chromium/src/base/shared_memory_win.cc +++ b/ipc/chromium/src/base/shared_memory_win.cc @@ -19,34 +19,20 @@ SharedMemory::SharedMemory() lock_(NULL) { } -SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only) - : mapped_file_(handle), - memory_(NULL), - read_only_(read_only), - max_size_(0), - lock_(NULL) { -} - -SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only, - ProcessHandle process) - : mapped_file_(NULL), - memory_(NULL), - read_only_(read_only), - max_size_(0), - lock_(NULL) { - ::DuplicateHandle(process, handle, - GetCurrentProcess(), &mapped_file_, - STANDARD_RIGHTS_REQUIRED | - (read_only_ ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS), - FALSE, 0); -} - SharedMemory::~SharedMemory() { Close(); if (lock_ != NULL) CloseHandle(lock_); } +bool SharedMemory::SetHandle(SharedMemoryHandle handle, bool read_only) { + DCHECK(mapped_file_ == NULL); + + mapped_file_ = handle; + read_only_ = read_only; + return true; +} + // static bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) { return handle != NULL; @@ -151,10 +137,9 @@ bool SharedMemory::ShareToProcessCommon(ProcessId processId, } -void SharedMemory::Close() { - if (memory_ != NULL) { - UnmapViewOfFile(memory_); - memory_ = NULL; +void SharedMemory::Close(bool unmap_view) { + if (unmap_view) { + Unmap(); } if (mapped_file_ != NULL) { diff --git a/ipc/glue/CrossProcessMutex_posix.cpp b/ipc/glue/CrossProcessMutex_posix.cpp index 3418a785cc20..3a6108ecadab 100644 --- a/ipc/glue/CrossProcessMutex_posix.cpp +++ b/ipc/glue/CrossProcessMutex_posix.cpp @@ -82,11 +82,15 @@ CrossProcessMutex::CrossProcessMutex(CrossProcessMutexHandle aHandle) : mMutex(nullptr) , mCount(nullptr) { - if (!ipc::SharedMemoryBasic::IsHandleValid(aHandle)) { + mSharedBuffer = new ipc::SharedMemoryBasic; + + if (!mSharedBuffer->IsHandleValid(aHandle)) { MOZ_CRASH(); } - mSharedBuffer = new ipc::SharedMemoryBasic(aHandle); + if (!mSharedBuffer->SetHandle(aHandle)) { + MOZ_CRASH(); + } if (!mSharedBuffer->Map(sizeof(MutexData))) { MOZ_CRASH(); diff --git a/ipc/glue/MessageLink.cpp b/ipc/glue/MessageLink.cpp index 14edb93b00a8..75e12500086d 100644 --- a/ipc/glue/MessageLink.cpp +++ b/ipc/glue/MessageLink.cpp @@ -16,7 +16,7 @@ #include "mozilla/dom/ContentParent.h" #include "mozilla/dom/PNuwa.h" #include "mozilla/hal_sandbox/PHal.h" -#if defined(DEBUG) || defined(ENABLE_TESTS) +#ifdef DEBUG #include "jsprf.h" extern "C" char* PrintJSStack(); #endif @@ -202,18 +202,17 @@ ProcessLink::SendMessage(Message *msg) } } +#if defined(DEBUG) // Nuwa to parent: check whether we are currently blocked. if (IsNuwaProcess() && mIsBlocked) { -#if defined(ENABLE_TESTS) || defined(DEBUG) char* jsstack = PrintJSStack(); printf_stderr("Fatal error: sending a message to the chrome process" "with a blocked IPC channel from \n%s", jsstack ? jsstack : ""); JS_smprintf_free(jsstack); MOZ_CRASH(); -#endif } - +#endif #endif mIOLoop->PostTask( diff --git a/ipc/glue/ProtocolUtils.h b/ipc/glue/ProtocolUtils.h index ac87acc439c3..36bc3bf5b94f 100644 --- a/ipc/glue/ProtocolUtils.h +++ b/ipc/glue/ProtocolUtils.h @@ -173,7 +173,6 @@ public: virtual Shmem::SharedMemory* CreateSharedMemory( size_t, SharedMemory::SharedMemoryType, bool, int32_t*) = 0; - virtual bool AdoptSharedMemory(Shmem::SharedMemory*, int32_t*) = 0; virtual Shmem::SharedMemory* LookupSharedMemory(int32_t) = 0; virtual bool IsTrackingSharedMemory(Shmem::SharedMemory*) = 0; virtual bool DestroySharedMemory(Shmem&) = 0; diff --git a/ipc/glue/SharedMemory.h b/ipc/glue/SharedMemory.h index 6a36aed7e96f..74f9fc881f7a 100644 --- a/ipc/glue/SharedMemory.h +++ b/ipc/glue/SharedMemory.h @@ -12,6 +12,9 @@ #include "nsISupportsImpl.h" // NS_INLINE_DECL_REFCOUNTING #include "mozilla/Attributes.h" +#include "base/process.h" +#include "chrome/common/ipc_message_utils.h" + // // This is a low-level wrapper around platform shared memory. Don't // use it directly; use Shmem allocated through IPDL interfaces. @@ -44,7 +47,6 @@ protected: public: enum SharedMemoryType { TYPE_BASIC, - TYPE_SYSV, TYPE_UNKNOWN }; @@ -55,8 +57,13 @@ public: virtual bool Create(size_t size) = 0; virtual bool Map(size_t nBytes) = 0; + virtual void CloseHandle() = 0; + virtual SharedMemoryType Type() const = 0; + virtual bool ShareHandle(base::ProcessId aProcessId, IPC::Message* aMessage) = 0; + virtual bool ReadHandle(const IPC::Message* aMessage, void** aIter) = 0; + void Protect(char* aAddr, size_t aSize, int aRights) { @@ -110,6 +117,35 @@ protected: size_t mMappedSize; }; +template +class SharedMemoryCommon : public SharedMemory +{ +public: + typedef HandleImpl Handle; + + virtual bool ShareToProcess(base::ProcessId aProcessId, Handle* aHandle) = 0; + virtual bool IsHandleValid(const Handle& aHandle) const = 0; + virtual bool SetHandle(const Handle& aHandle) = 0; + + virtual bool ShareHandle(base::ProcessId aProcessId, IPC::Message* aMessage) override + { + Handle handle; + if (!ShareToProcess(aProcessId, &handle)) { + return false; + } + IPC::WriteParam(aMessage, handle); + return true; + } + + virtual bool ReadHandle(const IPC::Message* aMessage, void** aIter) override + { + Handle handle; + return IPC::ReadParam(aMessage, aIter, &handle) && + IsHandleValid(handle) && + SetHandle(handle); + } +}; + } // namespace ipc } // namespace mozilla diff --git a/ipc/glue/SharedMemoryBasic_android.cpp b/ipc/glue/SharedMemoryBasic_android.cpp index 729023003f2f..eb91794b6ee7 100644 --- a/ipc/glue/SharedMemoryBasic_android.cpp +++ b/ipc/glue/SharedMemoryBasic_android.cpp @@ -40,15 +40,18 @@ SharedMemoryBasic::SharedMemoryBasic() , mMemory(nullptr) { } -SharedMemoryBasic::SharedMemoryBasic(const Handle& aHandle) - : mShmFd(aHandle.fd) - , mMemory(nullptr) -{ } - SharedMemoryBasic::~SharedMemoryBasic() { Unmap(); - Destroy(); + CloseHandle(); +} + +bool +SharedMemoryBasic::SetHandle(const Handle& aHandle) +{ + MOZ_ASSERT(-1 == mShmFd, "Already Create()d"); + mShmFd = aHandle.fd; + return true; } bool @@ -125,7 +128,7 @@ SharedMemoryBasic::Unmap() } void -SharedMemoryBasic::Destroy() +SharedMemoryBasic::CloseHandle() { if (mShmFd > 0) { close(mShmFd); diff --git a/ipc/glue/SharedMemoryBasic_android.h b/ipc/glue/SharedMemoryBasic_android.h index b10d8d769c57..3074f2d5b217 100644 --- a/ipc/glue/SharedMemoryBasic_android.h +++ b/ipc/glue/SharedMemoryBasic_android.h @@ -20,19 +20,19 @@ namespace mozilla { namespace ipc { -class SharedMemoryBasic final : public SharedMemory +class SharedMemoryBasic final : public SharedMemoryCommon { public: - typedef base::FileDescriptor Handle; - SharedMemoryBasic(); - SharedMemoryBasic(const Handle& aHandle); + virtual bool SetHandle(const Handle& aHandle) override; virtual bool Create(size_t aNbytes) override; virtual bool Map(size_t nBytes) override; + virtual void CloseHandle() override; + virtual void* memory() const override { return mMemory; @@ -48,19 +48,18 @@ public: return Handle(); } - static bool IsHandleValid(const Handle &aHandle) + virtual bool IsHandleValid(const Handle &aHandle) const override { return aHandle.fd >= 0; } - bool ShareToProcess(base::ProcessId aProcessId, - Handle* aNewHandle); + virtual bool ShareToProcess(base::ProcessId aProcessId, + Handle* aNewHandle) override; private: ~SharedMemoryBasic(); void Unmap(); - void Destroy(); // The /dev/ashmem fd we allocate. int mShmFd; diff --git a/ipc/glue/SharedMemoryBasic_chromium.h b/ipc/glue/SharedMemoryBasic_chromium.h index 97fd1ba623aa..6dfc6eafefbb 100644 --- a/ipc/glue/SharedMemoryBasic_chromium.h +++ b/ipc/glue/SharedMemoryBasic_chromium.h @@ -21,18 +21,15 @@ namespace mozilla { namespace ipc { -class SharedMemoryBasic final : public SharedMemory +class SharedMemoryBasic final : public SharedMemoryCommon { public: - typedef base::SharedMemoryHandle Handle; - SharedMemoryBasic() { } - explicit SharedMemoryBasic(const Handle& aHandle) - : mSharedMemory(aHandle, false) - { + virtual bool SetHandle(const Handle& aHandle) override { + return mSharedMemory.SetHandle(aHandle, false); } virtual bool Create(size_t aNbytes) override @@ -53,6 +50,11 @@ public: return ok; } + virtual void CloseHandle() override + { + mSharedMemory.Close(false); + } + virtual void* memory() const override { return mSharedMemory.memory(); @@ -68,13 +70,13 @@ public: return base::SharedMemory::NULLHandle(); } - static bool IsHandleValid(const Handle &aHandle) + virtual bool IsHandleValid(const Handle &aHandle) const override { return base::SharedMemory::IsHandleValid(aHandle); } - bool ShareToProcess(base::ProcessId aProcessId, - Handle* new_handle) + virtual bool ShareToProcess(base::ProcessId aProcessId, + Handle* new_handle) override { base::SharedMemoryHandle handle; bool ret = mSharedMemory.ShareToProcess(aProcessId, &handle); diff --git a/ipc/glue/SharedMemoryBasic_mach.h b/ipc/glue/SharedMemoryBasic_mach.h index bd0753fe10ef..708970fc0d6d 100644 --- a/ipc/glue/SharedMemoryBasic_mach.h +++ b/ipc/glue/SharedMemoryBasic_mach.h @@ -25,11 +25,9 @@ class ReceivePort; namespace mozilla { namespace ipc { -class SharedMemoryBasic final : public SharedMemory +class SharedMemoryBasic final : public SharedMemoryCommon { public: - typedef mach_port_t Handle; - static void SetupMachMemory(pid_t pid, ReceivePort* listen_port, MachPortSender* listen_port_ack, @@ -43,12 +41,14 @@ public: SharedMemoryBasic(); - explicit SharedMemoryBasic(Handle aHandle); + virtual bool SetHandle(const Handle& aHandle) override; virtual bool Create(size_t aNbytes) override; virtual bool Map(size_t nBytes) override; + virtual void CloseHandle() override; + virtual void* memory() const override { return mMemory; @@ -65,16 +65,15 @@ public: } - static bool IsHandleValid(const Handle &aHandle); + virtual bool IsHandleValid(const Handle &aHandle) const override; - bool ShareToProcess(base::ProcessId aProcessId, - Handle* aNewHandle); + virtual bool ShareToProcess(base::ProcessId aProcessId, + Handle* aNewHandle) override; private: ~SharedMemoryBasic(); void Unmap(); - void Destroy(); mach_port_t mPort; // Pointer to mapped region, null if unmapped. void *mMemory; diff --git a/ipc/glue/SharedMemoryBasic_mach.mm b/ipc/glue/SharedMemoryBasic_mach.mm index 79bce0ea0c83..35ebd979a10f 100644 --- a/ipc/glue/SharedMemoryBasic_mach.mm +++ b/ipc/glue/SharedMemoryBasic_mach.mm @@ -500,17 +500,19 @@ SharedMemoryBasic::SharedMemoryBasic() { } -SharedMemoryBasic::SharedMemoryBasic(Handle aHandle) - : mPort(MACH_PORT_NULL) - , mMemory(nullptr) -{ - mPort = aHandle; -} - SharedMemoryBasic::~SharedMemoryBasic() { Unmap(); - Destroy(); + CloseHandle(); +} + +bool +SharedMemoryBasic::SetHandle(const Handle& aHandle) +{ + MOZ_ASSERT(mPort == MACH_PORT_NULL, "already initialized"); + + mPort = aHandle; + return true; } static inline void* @@ -657,13 +659,16 @@ SharedMemoryBasic::Unmap() } void -SharedMemoryBasic::Destroy() +SharedMemoryBasic::CloseHandle() { - mach_port_deallocate(mach_task_self(), mPort); + if (mPort != MACH_PORT_NULL) { + mach_port_deallocate(mach_task_self(), mPort); + mPort = MACH_PORT_NULL; + } } bool -SharedMemoryBasic::IsHandleValid(const Handle& aHandle) +SharedMemoryBasic::IsHandleValid(const Handle& aHandle) const { return aHandle > 0; } diff --git a/ipc/glue/SharedMemorySysV.h b/ipc/glue/SharedMemorySysV.h deleted file mode 100644 index 934569300665..000000000000 --- a/ipc/glue/SharedMemorySysV.h +++ /dev/null @@ -1,150 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * vim: sw=2 ts=8 et : - */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_ipc_SharedMemorySysV_h -#define mozilla_ipc_SharedMemorySysV_h - -#if (defined(OS_LINUX) && !defined(ANDROID)) || defined(OS_BSD) - -// SysV shared memory isn't available on Windows, but we define the -// following macro so that #ifdefs are clearer (compared to #ifdef -// OS_LINUX). -#define MOZ_HAVE_SHAREDMEMORYSYSV - -#include "SharedMemory.h" - -#include "nsDebug.h" - -#include -#include -#include -#include -#include -#include - -// -// This is a low-level wrapper around platform shared memory. Don't -// use it directly; use Shmem allocated through IPDL interfaces. -// - -namespace mozilla { -namespace ipc { - - -class SharedMemorySysV : public SharedMemory -{ -public: - typedef int Handle; - - SharedMemorySysV() : - mHandle(-1), - mData(nullptr) - { - } - - explicit SharedMemorySysV(Handle aHandle) : - mHandle(aHandle), - mData(nullptr) - { - } - - virtual ~SharedMemorySysV() - { - shmdt(mData); - mHandle = -1; - mData = nullptr; - } - - virtual bool Create(size_t aNbytes) override - { - int id = shmget(IPC_PRIVATE, aNbytes, IPC_CREAT | 0600); - if (id == -1) - return false; - - mHandle = id; - mAllocSize = aNbytes; - Created(aNbytes); - - return Map(aNbytes); - } - - virtual bool Map(size_t nBytes) override - { - // already mapped - if (mData) - return true; - - if (!IsHandleValid(mHandle)) - return false; - - void* mem = shmat(mHandle, nullptr, 0); - if (mem == (void*) -1) { - char warning[256]; - ::snprintf(warning, sizeof(warning)-1, - "shmat(): %s (%d)\n", strerror(errno), errno); - - NS_WARNING(warning); - - return false; - } - - // Mark the handle as deleted so that, should this process go away, the - // segment is cleaned up. - shmctl(mHandle, IPC_RMID, 0); - - mData = mem; - -#ifdef DEBUG - struct shmid_ds info; - if (shmctl(mHandle, IPC_STAT, &info) < 0) - return false; - - MOZ_ASSERT(nBytes <= info.shm_segsz, - "Segment doesn't have enough space!"); -#endif - - Mapped(nBytes); - return true; - } - - virtual void* memory() const override - { - return mData; - } - - virtual SharedMemoryType Type() const override - { - return TYPE_SYSV; - } - - Handle GetHandle() const - { - MOZ_ASSERT(IsHandleValid(mHandle), "invalid handle"); - return mHandle; - } - - static Handle NULLHandle() - { - return -1; - } - - static bool IsHandleValid(Handle aHandle) - { - return aHandle != -1; - } - -private: - Handle mHandle; - void* mData; -}; - -} // namespace ipc -} // namespace mozilla - -#endif // OS_LINUX - -#endif // ifndef mozilla_ipc_SharedMemorySysV_h diff --git a/ipc/glue/Shmem.cpp b/ipc/glue/Shmem.cpp index d14be9f2514f..31d8af9b3dcf 100644 --- a/ipc/glue/Shmem.cpp +++ b/ipc/glue/Shmem.cpp @@ -9,7 +9,6 @@ #include "ProtocolUtils.h" #include "SharedMemoryBasic.h" -#include "SharedMemorySysV.h" #include "mozilla/unused.h" @@ -24,22 +23,16 @@ private: public: ShmemCreated(int32_t routingId, - const id_t& aIPDLId, - const size_t& aSize, - const SharedMemoryBasic::Handle& aHandle) : + id_t aIPDLId, + size_t aSize, + SharedMemory::SharedMemoryType aType) : IPC::Message(routingId, SHMEM_CREATED_MESSAGE_TYPE, PRIORITY_NORMAL) { IPC::WriteParam(this, aIPDLId); IPC::WriteParam(this, aSize); - IPC::WriteParam(this, int32_t(SharedMemory::TYPE_BASIC)), - IPC::WriteParam(this, aHandle); + IPC::WriteParam(this, int32_t(aType)); } - // Instead of a single Read() function, we have ReadInfo() and - // ReadHandle(). The reason is that the handle type is specific to - // the shmem type. These functions should only be called in the - // order ReadInfo(); ReadHandle();, and only once each. - static bool ReadInfo(const Message* msg, void** iter, id_t* aIPDLId, @@ -53,40 +46,6 @@ public: return true; } - static bool - ReadHandle(const Message* msg, void** iter, - SharedMemoryBasic::Handle* aHandle) - { - if (!IPC::ReadParam(msg, iter, aHandle)) - return false; - msg->EndRead(*iter); - return true; - } - -#ifdef MOZ_HAVE_SHAREDMEMORYSYSV - ShmemCreated(int32_t routingId, - const id_t& aIPDLId, - const size_t& aSize, - const SharedMemorySysV::Handle& aHandle) : - IPC::Message(routingId, SHMEM_CREATED_MESSAGE_TYPE, PRIORITY_NORMAL) - { - IPC::WriteParam(this, aIPDLId); - IPC::WriteParam(this, aSize); - IPC::WriteParam(this, int32_t(SharedMemory::TYPE_SYSV)), - IPC::WriteParam(this, aHandle); - } - - static bool - ReadHandle(const Message* msg, void** iter, - SharedMemorySysV::Handle* aHandle) - { - if (!IPC::ReadParam(msg, iter, aHandle)) - return false; - msg->EndRead(*iter); - return true; - } -#endif - void Log(const std::string& aPrefix, FILE* aOutf) const { @@ -101,53 +60,65 @@ private: public: ShmemDestroyed(int32_t routingId, - const id_t& aIPDLId) : + id_t aIPDLId) : IPC::Message(routingId, SHMEM_DESTROYED_MESSAGE_TYPE, PRIORITY_NORMAL) { IPC::WriteParam(this, aIPDLId); } }; - -#ifdef MOZ_HAVE_SHAREDMEMORYSYSV -static already_AddRefed -CreateSegment(size_t aNBytes, SharedMemorySysV::Handle aHandle) +static SharedMemory* +NewSegment(SharedMemory::SharedMemoryType aType) { - RefPtr segment; - - if (SharedMemorySysV::IsHandleValid(aHandle)) { - segment = new SharedMemorySysV(aHandle); - } - else { - segment = new SharedMemorySysV(); - - if (!segment->Create(aNBytes)) - return nullptr; - } - if (!segment->Map(aNBytes)) + if (SharedMemory::TYPE_BASIC == aType) { + return new SharedMemoryBasic; + } else { + NS_ERROR("unknown Shmem type"); return nullptr; + } +} +static already_AddRefed +CreateSegment(SharedMemory::SharedMemoryType aType, size_t aNBytes, size_t aExtraSize) +{ + RefPtr segment = NewSegment(aType); + if (!segment) { + return nullptr; + } + size_t size = SharedMemory::PageAlignedSize(aNBytes + aExtraSize); + if (!segment->Create(size) || !segment->Map(size)) { + return nullptr; + } return segment.forget(); } -#endif -static already_AddRefed -CreateSegment(size_t aNBytes, SharedMemoryBasic::Handle aHandle) +static already_AddRefed +ReadSegment(const IPC::Message& aDescriptor, Shmem::id_t* aId, size_t* aNBytes, size_t aExtraSize) { - RefPtr segment; - - if (SharedMemoryBasic::IsHandleValid(aHandle)) { - segment = new SharedMemoryBasic(aHandle); - } - else { - segment = new SharedMemoryBasic(); - - if (!segment->Create(aNBytes)) - return nullptr; - } - if (!segment->Map(aNBytes)) + if (SHMEM_CREATED_MESSAGE_TYPE != aDescriptor.type()) { + NS_ERROR("expected 'shmem created' message"); return nullptr; - + } + SharedMemory::SharedMemoryType type; + void* iter = nullptr; + if (!ShmemCreated::ReadInfo(&aDescriptor, &iter, aId, aNBytes, &type)) { + return nullptr; + } + RefPtr segment = NewSegment(type); + if (!segment) { + return nullptr; + } + if (!segment->ReadHandle(&aDescriptor, &iter)) { + NS_ERROR("trying to open invalid handle"); + return nullptr; + } + aDescriptor.EndRead(iter); + size_t size = SharedMemory::PageAlignedSize(*aNBytes + aExtraSize); + if (!segment->Map(size)) { + return nullptr; + } + // close the handle to the segment after it is mapped + segment->CloseHandle(); return segment.forget(); } @@ -155,8 +126,9 @@ static void DestroySegment(SharedMemory* aSegment) { // the SharedMemory dtor closes and unmaps the actual OS shmem segment - if (aSegment) + if (aSegment) { aSegment->Release(); + } } @@ -357,24 +329,12 @@ Shmem::Alloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead, MOZ_ASSERT(!aProtect || !aUnsafe, "protect => !unsafe"); size_t pageSize = SharedMemory::SystemPageSize(); - RefPtr segment; // |2*pageSize| is for the front and back sentinel - size_t segmentSize = SharedMemory::PageAlignedSize(aNBytes + 2*pageSize); - - if (aType == SharedMemory::TYPE_BASIC) - segment = CreateSegment(segmentSize, SharedMemoryBasic::NULLHandle()); -#ifdef MOZ_HAVE_SHAREDMEMORYSYSV - else if (aType == SharedMemory::TYPE_SYSV) - segment = CreateSegment(segmentSize, SharedMemorySysV::NULLHandle()); -#endif - else { - NS_ERROR("unknown shmem type"); + RefPtr segment = CreateSegment(aType, aNBytes, 2*pageSize); + if (!segment) { return nullptr; } - if (!segment) - return nullptr; - Header* header; char *frontSentinel; char *data; @@ -405,54 +365,14 @@ Shmem::OpenExisting(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead, id_t* aId, bool aProtect) { - if (SHMEM_CREATED_MESSAGE_TYPE != aDescriptor.type()) { - NS_ERROR("expected 'shmem created' message"); - return nullptr; - } - - void* iter = nullptr; - SharedMemory::SharedMemoryType type; size_t size; - if (!ShmemCreated::ReadInfo(&aDescriptor, &iter, aId, &size, &type)) - return nullptr; - - RefPtr segment; size_t pageSize = SharedMemory::SystemPageSize(); // |2*pageSize| is for the front and back sentinels - size_t segmentSize = SharedMemory::PageAlignedSize(size + 2*pageSize); - - if (SharedMemory::TYPE_BASIC == type) { - SharedMemoryBasic::Handle handle; - if (!ShmemCreated::ReadHandle(&aDescriptor, &iter, &handle)) - return nullptr; - - if (!SharedMemoryBasic::IsHandleValid(handle)) { - NS_ERROR("trying to open invalid handle"); - return nullptr; - } - segment = CreateSegment(segmentSize, handle); - } -#ifdef MOZ_HAVE_SHAREDMEMORYSYSV - else if (SharedMemory::TYPE_SYSV == type) { - SharedMemorySysV::Handle handle; - if (!ShmemCreated::ReadHandle(&aDescriptor, &iter, &handle)) - return nullptr; - - if (!SharedMemorySysV::IsHandleValid(handle)) { - NS_ERROR("trying to open invalid handle"); - return nullptr; - } - segment = CreateSegment(segmentSize, handle); - } -#endif - else { - NS_ERROR("unknown shmem type"); + RefPtr segment = ReadSegment(aDescriptor, aId, &size, 2*pageSize); + if (!segment) { return nullptr; } - if (!segment) - return nullptr; - Header* header = GetHeader(segment); if (size != header->mSize) { @@ -508,23 +428,11 @@ Shmem::Alloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead, bool /*unused*/, bool /*unused*/) { - RefPtr segment; - - if (aType == SharedMemory::TYPE_BASIC) - segment = CreateSegment(SharedMemory::PageAlignedSize(aNBytes + sizeof(uint32_t)), - SharedMemoryBasic::NULLHandle()); -#ifdef MOZ_HAVE_SHAREDMEMORYSYSV - else if (aType == SharedMemory::TYPE_SYSV) - segment = CreateSegment(SharedMemory::PageAlignedSize(aNBytes + sizeof(uint32_t)), - SharedMemorySysV::NULLHandle()); -#endif - else { + RefPtr segment = CreateSegment(aType, aNBytes, sizeof(uint32_t)); + if (!segment) { return nullptr; } - if (!segment) - return nullptr; - *PtrToSize(segment) = static_cast(aNBytes); return segment.forget(); @@ -537,49 +445,12 @@ Shmem::OpenExisting(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead, id_t* aId, bool /*unused*/) { - if (SHMEM_CREATED_MESSAGE_TYPE != aDescriptor.type()) { - return nullptr; - } - - SharedMemory::SharedMemoryType type; - void* iter = nullptr; size_t size; - if (!ShmemCreated::ReadInfo(&aDescriptor, &iter, aId, &size, &type)) - return nullptr; - - RefPtr segment; - size_t segmentSize = SharedMemory::PageAlignedSize(size + sizeof(uint32_t)); - - if (SharedMemory::TYPE_BASIC == type) { - SharedMemoryBasic::Handle handle; - if (!ShmemCreated::ReadHandle(&aDescriptor, &iter, &handle)) - return nullptr; - - if (!SharedMemoryBasic::IsHandleValid(handle)) { - return nullptr; - } - - segment = CreateSegment(segmentSize, handle); - } -#ifdef MOZ_HAVE_SHAREDMEMORYSYSV - else if (SharedMemory::TYPE_SYSV == type) { - SharedMemorySysV::Handle handle; - if (!ShmemCreated::ReadHandle(&aDescriptor, &iter, &handle)) - return nullptr; - - if (!SharedMemorySysV::IsHandleValid(handle)) { - return nullptr; - } - segment = CreateSegment(segmentSize, handle); - } -#endif - else { + RefPtr segment = ReadSegment(aDescriptor, aId, &size, sizeof(uint32_t)); + if (!segment) { return nullptr; } - if (!segment) - return nullptr; - // this is the only validity check done in non-DEBUG builds if (size != static_cast(*PtrToSize(segment))) { return nullptr; @@ -598,25 +469,6 @@ Shmem::Dealloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead, #endif // if defined(DEBUG) -int -Shmem::GetSysVID() const -{ -#ifdef MOZ_HAVE_SHAREDMEMORYSYSV - AssertInvariants(); - - if (mSegment->Type() != SharedMemory::TYPE_SYSV) { - NS_ERROR("Can't call GetSysVID() on a non-SysV Shmem!"); - return -1; - } - - SharedMemorySysV* seg = static_cast(mSegment); - return seg->GetHandle(); -#else - NS_ERROR("Can't call GetSysVID() with no support for SysV shared memory!"); - return -1; // not reached -#endif -} - IPC::Message* Shmem::ShareTo(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead, base::ProcessId aTargetPid, @@ -624,26 +476,13 @@ Shmem::ShareTo(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead, { AssertInvariants(); - if (SharedMemory::TYPE_BASIC == mSegment->Type()) { - SharedMemoryBasic* seg = static_cast(mSegment); - SharedMemoryBasic::Handle handle; - if (!seg->ShareToProcess(aTargetPid, &handle)) - return nullptr; - - return new ShmemCreated(routingId, mId, mSize, handle); - } -#ifdef MOZ_HAVE_SHAREDMEMORYSYSV - else if (SharedMemory::TYPE_SYSV == mSegment->Type()) { - SharedMemorySysV* seg = static_cast(mSegment); - return new ShmemCreated(routingId, mId, mSize, seg->GetHandle()); - } -#endif - else { - MOZ_ASSERT(false, "unknown shmem type (here?!)"); + IPC::Message *msg = new ShmemCreated(routingId, mId, mSize, mSegment->Type()); + if (!mSegment->ShareHandle(aTargetPid, msg)) { return nullptr; } - - return nullptr; + // close the handle to the segment after it is shared + mSegment->CloseHandle(); + return msg; } IPC::Message* diff --git a/ipc/glue/Shmem.h b/ipc/glue/Shmem.h index 6e7cd0f99a28..afae28aa04ea 100644 --- a/ipc/glue/Shmem.h +++ b/ipc/glue/Shmem.h @@ -36,7 +36,7 @@ * means is OS specific.) * * (4a) The child receives the special IPC message, and using the - * |SharedMemory{SysV,Basic}::Handle| it was passed, creates a + * |SharedMemory{Basic}::Handle| it was passed, creates a * |mozilla::ipc::SharedMemory| in the child * process. * @@ -125,13 +125,7 @@ public: bool operator==(const Shmem& aRhs) const { - // need to compare IDs because of AdoptShmem(); two Shmems might - // refer to the same segment but with different IDs for different - // protocol trees. (NB: it's possible for this method to - // spuriously return true if AdoptShmem() gives the same ID for - // two protocol trees, but I don't think that can cause any - // problems since the Shmems really would be indistinguishable.) - return mSegment == aRhs.mSegment && mId == aRhs.mId; + return mSegment == aRhs.mSegment; } // Returns whether this Shmem is writable by you, and thus whether you can @@ -175,8 +169,6 @@ public: return mSize / sizeof(T); } - int GetSysVID() const; - // These shouldn't be used directly, use the IPDL interface instead. id_t Id(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead) const { return mId; diff --git a/ipc/glue/moz.build b/ipc/glue/moz.build index ff5503644658..e005ea81b125 100644 --- a/ipc/glue/moz.build +++ b/ipc/glue/moz.build @@ -31,7 +31,6 @@ EXPORTS.mozilla.ipc += [ 'ScopedXREEmbed.h', 'SharedMemory.h', 'SharedMemoryBasic.h', - 'SharedMemorySysV.h', 'Shmem.h', 'Transport.h', 'URIUtils.h', diff --git a/ipc/ipdl/ipdl/lower.py b/ipc/ipdl/ipdl/lower.py index 934d3b1d6dc5..619663d5f377 100644 --- a/ipc/ipdl/ipdl/lower.py +++ b/ipc/ipdl/ipdl/lower.py @@ -1120,9 +1120,6 @@ class Protocol(ipdl.ast.Protocol): def createSharedMemory(self): return ExprVar('CreateSharedMemory') - def adoptSharedMemory(self): - return ExprVar('AdoptSharedMemory') - def lookupSharedMemory(self): return ExprVar('LookupSharedMemory') @@ -3674,12 +3671,6 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor): Decl(Type.BOOL, unsafevar.name), Decl(_shmemIdType(ptr=1), idvar.name) ], virtual=1)) - adoptshmem = MethodDefn(MethodDecl( - p.adoptSharedMemory().name, - ret=Type.BOOL, - params=[ Decl(_rawShmemType(ptr=1), rawvar.name), - Decl(_shmemIdType(ptr=1), idvar.name) ], - virtual=1)) lookupshmem = MethodDefn(MethodDecl( p.lookupSharedMemory().name, ret=_rawShmemType(ptr=1), @@ -3796,48 +3787,6 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor): StmtReturn(rawsegmentvar) ]) - # SharedMemory* AdoptSharedMemory(SharedMemory*, id_t*): - # Shmem s(seg, [nextshmemid]); - # Message descriptor; - # if (!s->ShareTo(subprocess, mId, descriptor) || - # !Send(descriptor)) - # return false; - # mShmemMap.Add(seg, id); - # seg->AddRef(); - # return true; - - # XXX this is close to the same code as above, could be - # refactored - descriptorvar = ExprVar('descriptor') - adoptshmem.addstmts([ - StmtDecl( - Decl(_shmemType(), shmemvar.name), - initargs=[ _shmemBackstagePass(), - rawvar, - p.nextShmemIdExpr(self.side) ]), - StmtDecl(Decl(Type('Message', ptr=1), descriptorvar.name), - init=_shmemShareTo(shmemvar, - p.callOtherPid(), - p.routingId())) - ]) - failif = StmtIf(ExprNot(descriptorvar)) - failif.addifstmt(StmtReturn.FALSE) - adoptshmem.addstmt(failif) - - failif = StmtIf(ExprNot(ExprCall( - ExprSelect(p.channelVar(), p.channelSel(), 'Send'), - args=[ descriptorvar ]))) - adoptshmem.addstmt(failif) - - adoptshmem.addstmts([ - StmtExpr(ExprAssn(ExprDeref(idvar), _shmemId(shmemvar))), - StmtExpr(ExprCall( - ExprSelect(p.shmemMapVar(), '.', 'AddWithID'), - args=[ rawvar, ExprDeref(idvar) ])), - StmtExpr(ExprCall(ExprSelect(rawvar, '->', 'AddRef'))), - StmtReturn.TRUE - ]) - # SharedMemory* Lookup(id) lookupshmem.addstmt(StmtReturn(ExprCall( ExprSelect(p.shmemMapVar(), '.', 'Lookup'), @@ -3936,9 +3885,6 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor): createshmem.addstmt(StmtReturn(ExprCall( ExprSelect(p.managerVar(), '->', p.createSharedMemory().name), [ sizevar, typevar, unsafevar, idvar ]))) - adoptshmem.addstmt(StmtReturn(ExprCall( - ExprSelect(p.managerVar(), '->', p.adoptSharedMemory().name), - [ rawvar, idvar ]))) lookupshmem.addstmt(StmtReturn(ExprCall( ExprSelect(p.managerVar(), '->', p.lookupSharedMemory().name), [ idvar ]))) @@ -4091,7 +4037,6 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor): unregister, removemanagee, createshmem, - adoptshmem, lookupshmem, istracking, destroyshmem, @@ -4154,52 +4099,6 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor): # bool AllocUnsafeShmem(size_t size, Type type, Shmem* outmem): allocUnsafeShmem = allocShmemMethod('AllocUnsafeShmem', True) - # bool AdoptShmem(Shmem& aMem, Shmem* aOutmem): - # SharedMemory* rawmem = aMem.Segment(); - # if (!rawmem || IsTrackingSharedMemory(rawmem)) { - # NS_WARNING("bad Shmem"); // or NS_RUNTIMEABORT on child side - # return false; - # } - # id_t id - # if (!AdoptSharedMemory(rawmem, &id)) - # return false - # *aOutmem = Shmem(rawmem, id); - # return true; - adoptShmem = MethodDefn(MethodDecl( - 'AdoptShmem', - params=[ Decl(_shmemType(const=1, ref=1), memvar.name), - Decl(_shmemType(ptr=1), outmemvar.name) ], - ret=Type.BOOL)) - - adoptShmem.addstmt(StmtDecl(Decl(_rawShmemType(ptr=1), rawvar.name), - init=_shmemSegment(memvar))) - ifbad = StmtIf(ExprBinary( - ExprNot(rawvar), '||', - ExprCall(ExprVar('IsTrackingSharedMemory'), args=[ rawvar ]))) - badShmemActions = [] - if (self.side == 'child'): - badShmemActions.append(_runtimeAbort('bad Shmem')); - else: - badShmemActions.append(_printWarningMessage('bad Shmem')); - badShmemActions.append(StmtReturn.FALSE); - ifbad.addifstmts(badShmemActions) - - adoptShmem.addstmt(ifbad) - - ifadoptfails = StmtIf(ExprNot(ExprCall( - p.adoptSharedMemory(), args=[ rawvar, ExprAddrOf(idvar) ]))) - ifadoptfails.addifstmt(StmtReturn.FALSE) - - adoptShmem.addstmts([ - Whitespace.NL, - StmtDecl(Decl(_shmemIdType(), idvar.name)), - ifadoptfails, - Whitespace.NL, - StmtExpr(ExprAssn(ExprDeref(outmemvar), - _shmemCtor(rawvar, idvar))), - StmtReturn.TRUE - ]) - # bool DeallocShmem(Shmem& mem): # bool ok = DestroySharedMemory(mem); ##ifdef DEBUG @@ -4217,6 +4116,12 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor): okvar = ExprVar('ok') ifbad = StmtIf(ExprNot(okvar)) + badShmemActions = [] + if (self.side == 'child'): + badShmemActions.append(_runtimeAbort('bad Shmem')); + else: + badShmemActions.append(_printWarningMessage('bad Shmem')); + badShmemActions.append(StmtReturn.FALSE); ifbad.addifstmts(badShmemActions) deallocShmem.addstmts([ @@ -4235,8 +4140,6 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor): Whitespace.NL, allocUnsafeShmem, Whitespace.NL, - adoptShmem, - Whitespace.NL, deallocShmem, Whitespace.NL ] diff --git a/ipc/ipdl/test/cxx/PTestSysVShmem.ipdl b/ipc/ipdl/test/cxx/PTestSysVShmem.ipdl deleted file mode 100644 index 56c01c54a741..000000000000 --- a/ipc/ipdl/test/cxx/PTestSysVShmem.ipdl +++ /dev/null @@ -1,22 +0,0 @@ -namespace mozilla { -namespace _ipdltest { - -protocol PTestSysVShmem { -child: - async Give(Shmem mem, Shmem unsafe, size_t expectedSize); - -parent: - async Take(Shmem mem, Shmem unsafe, size_t expectedSize); - async __delete__(); - - -state GIVING: - send Give goto TAKING; - -state TAKING: - recv Take goto TAKING; - recv __delete__; -}; - -} -} diff --git a/ipc/ipdl/test/cxx/TestSysVShmem.cpp b/ipc/ipdl/test/cxx/TestSysVShmem.cpp deleted file mode 100644 index bd41c1f47a28..000000000000 --- a/ipc/ipdl/test/cxx/TestSysVShmem.cpp +++ /dev/null @@ -1,120 +0,0 @@ -#include "TestSysVShmem.h" - -#include "IPDLUnitTests.h" // fail etc. - - -namespace mozilla { -namespace _ipdltest { - -//----------------------------------------------------------------------------- -// Parent - -void -TestSysVShmemParent::Main() -{ - Shmem mem; - Shmem unsafe; - - size_t size = 12345; - if (!AllocShmem(size, SharedMemory::TYPE_SYSV, &mem)) - fail("can't alloc shmem"); - if (!AllocUnsafeShmem(size, SharedMemory::TYPE_SYSV, &unsafe)) - fail("can't alloc shmem"); - - if (0 > mem.GetSysVID()) - fail("invalid shmem ID"); - if (0 > unsafe.GetSysVID()) - fail("invalid shmem ID"); - - if (mem.Size() != size) - fail("shmem is wrong size: expected %lu, got %lu", - size, mem.Size()); - if (unsafe.Size() != size) - fail("shmem is wrong size: expected %lu, got %lu", - size, unsafe.Size()); - - char* ptr = mem.get(); - memcpy(ptr, "Hello!", sizeof("Hello!")); - - char* unsafeptr = unsafe.get(); - memcpy(unsafeptr, "Hello!", sizeof("Hello!")); - - Shmem unsafecopy = unsafe; - if (!SendGive(mem, unsafe, size)) - fail("can't send Give()"); - - // uncomment the following line for a (nondeterministic) surprise! - //char c1 = *ptr; (void)c1; - - // uncomment the following line for a deterministic surprise! - //char c2 = *mem.get(); (void)c2; - - // unsafe shmem gets rid of those checks - char uc1 = *unsafeptr; (void)uc1; - char uc2 = *unsafecopy.get(); (void)uc2; -} - - -bool -TestSysVShmemParent::RecvTake(Shmem&& mem, Shmem&& unsafe, - const size_t& expectedSize) -{ - if (mem.Size() != expectedSize) - fail("expected shmem size %lu, but it has size %lu", - expectedSize, mem.Size()); - if (unsafe.Size() != expectedSize) - fail("expected shmem size %lu, but it has size %lu", - expectedSize, unsafe.Size()); - - if (strcmp(mem.get(), "And yourself!")) - fail("expected message was not written"); - if (strcmp(unsafe.get(), "And yourself!")) - fail("expected message was not written"); - - if (!DeallocShmem(mem)) - fail("DeallocShmem"); - if (!DeallocShmem(unsafe)) - fail("DeallocShmem"); - - Close(); - - return true; -} - -//----------------------------------------------------------------------------- -// Child - -bool -TestSysVShmemChild::RecvGive(Shmem&& mem, Shmem&& unsafe, const size_t& expectedSize) -{ - if (mem.Size() != expectedSize) - fail("expected shmem size %lu, but it has size %lu", - expectedSize, mem.Size()); - if (unsafe.Size() != expectedSize) - fail("expected shmem size %lu, but it has size %lu", - expectedSize, unsafe.Size()); - - if (strcmp(mem.get(), "Hello!")) - fail("expected message was not written"); - if (strcmp(unsafe.get(), "Hello!")) - fail("expected message was not written"); - - char* unsafeptr = unsafe.get(); - - memcpy(mem.get(), "And yourself!", sizeof("And yourself!")); - memcpy(unsafeptr, "And yourself!", sizeof("And yourself!")); - - Shmem unsafecopy = unsafe; - if (!SendTake(mem, unsafe, expectedSize)) - fail("can't send Take()"); - - // these checks also shouldn't fail in the child - char uc1 = *unsafeptr; (void)uc1; - char uc2 = *unsafecopy.get(); (void)uc2; - - return true; -} - - -} // namespace _ipdltest -} // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestSysVShmem.h b/ipc/ipdl/test/cxx/TestSysVShmem.h deleted file mode 100644 index bbba0a116653..000000000000 --- a/ipc/ipdl/test/cxx/TestSysVShmem.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef mozilla__ipdltest_TestSysVShmem_h -#define mozilla__ipdltest_TestSysVShmem_h - -#include "mozilla/_ipdltest/IPDLUnitTests.h" - -#include "mozilla/_ipdltest/PTestSysVShmemParent.h" -#include "mozilla/_ipdltest/PTestSysVShmemChild.h" - -namespace mozilla { -namespace _ipdltest { - - -class TestSysVShmemParent : - public PTestSysVShmemParent -{ -public: - TestSysVShmemParent() { } - virtual ~TestSysVShmemParent() { } - - static bool RunTestInProcesses() { return true; } - static bool RunTestInThreads() { return true; } - - void Main(); - -protected: - virtual bool RecvTake( - Shmem&& mem, - Shmem&& unsafe, - const size_t& expectedSize) override; - - virtual void ActorDestroy(ActorDestroyReason why) override - { - if (NormalShutdown != why) - fail("unexpected destruction!"); - passed("ok"); - QuitParent(); - } -}; - - -class TestSysVShmemChild : - public PTestSysVShmemChild -{ -public: - TestSysVShmemChild() { } - virtual ~TestSysVShmemChild() { } - -protected: - virtual bool RecvGive( - Shmem&& mem, - Shmem&& unsafe, - const size_t& expectedSize) override; - - virtual void ActorDestroy(ActorDestroyReason why) override - { - if (NormalShutdown != why) - fail("unexpected destruction!"); - QuitChild(); - } -}; - - -} // namespace _ipdltest -} // namespace mozilla - -#endif // ifndef mozilla__ipdltest_TestSysVShmem_h diff --git a/ipc/ipdl/test/cxx/moz.build b/ipc/ipdl/test/cxx/moz.build index 42d51de41c6e..fc04858b4289 100644 --- a/ipc/ipdl/test/cxx/moz.build +++ b/ipc/ipdl/test/cxx/moz.build @@ -53,11 +53,6 @@ SOURCES += [ 'TestUrgentHangs.cpp', ] -if CONFIG['OS_ARCH'] == 'Linux': - SOURCES += [ - 'TestSysVShmem.cpp', - ] - SOURCES += [ '!IPDLUnitTests.cpp', 'IPDLUnitTestProcessChild.cpp', @@ -127,7 +122,6 @@ IPDL_SOURCES += [ 'PTestSyncError.ipdl', 'PTestSyncHang.ipdl', 'PTestSyncWakeup.ipdl', - 'PTestSysVShmem.ipdl', 'PTestUrgency.ipdl', 'PTestUrgentHangs.ipdl', ] diff --git a/js/src/asmjs/AsmJS.cpp b/js/src/asmjs/AsmJS.cpp index 70a052ad12f5..db468e166761 100644 --- a/js/src/asmjs/AsmJS.cpp +++ b/js/src/asmjs/AsmJS.cpp @@ -918,6 +918,10 @@ ParseVarOrConstStatement(AsmJSParser& parser, ParseNode** var) // out of range: otherwise // Lastly, a literal may be a float literal which is any double or integer // literal coerced with Math.fround. +// +// This class distinguishes between signed and unsigned integer SIMD types like +// Int32x4 and Uint32x4, and so does Type below. The wasm ValType and ExprType +// enums, and the wasm::Val class do not. class NumLit { public: @@ -928,6 +932,7 @@ class NumLit Double, Float, Int32x4, + Uint32x4, Float32x4, Bool32x4, OutOfRangeInt = -1 @@ -982,7 +987,8 @@ class NumLit } bool isSimd() const { - return which_ == Int32x4 || which_ == Float32x4 || which_ == Bool32x4; + return which_ == Int32x4 || which_ == Uint32x4 || which_ == Float32x4 || + which_ == Bool32x4; } const SimdConstant& simdValue() const { @@ -1006,6 +1012,7 @@ class NumLit case NumLit::Float: return toFloat() == 0.f && !IsNegativeZero(toFloat()); case NumLit::Int32x4: + case NumLit::Uint32x4: return simdValue() == SimdConstant::SplatX4(0); case NumLit::Float32x4: return simdValue() == SimdConstant::SplatX4(0.f); @@ -1017,27 +1024,6 @@ class NumLit return false; } - ValType type() const { - switch (which_) { - case NumLit::Fixnum: - case NumLit::NegativeInt: - case NumLit::BigUnsigned: - return ValType::I32; - case NumLit::Double: - return ValType::F64; - case NumLit::Float: - return ValType::F32; - case NumLit::Int32x4: - return ValType::I32x4; - case NumLit::Float32x4: - return ValType::F32x4; - case NumLit::Bool32x4: - return ValType::B32x4; - case NumLit::OutOfRangeInt:; - } - MOZ_CRASH("bad literal"); - } - Val value() const { switch (which_) { case NumLit::Fixnum: @@ -1049,6 +1035,7 @@ class NumLit case NumLit::Double: return Val(toDouble()); case NumLit::Int32x4: + case NumLit::Uint32x4: return Val(simdValue().asInt32x4()); case NumLit::Float32x4: return Val(simdValue().asFloat32x4()); @@ -1060,7 +1047,20 @@ class NumLit } }; -// Respresents the type of a general asm.js expression. +// Represents the type of a general asm.js expression. +// +// A canonical subset of types representing the coercion targets: Int, Float, +// Double, and the SIMD types. This is almost equivalent to wasm::ValType, +// except the integer SIMD types have signed/unsigned variants. +// +// Void is also part of the canonical subset which then maps to wasm::ExprType. +// +// Note that while the canonical subset distinguishes signed and unsigned SIMD +// types, it only uses |Int| to represent signed and unsigned 32-bit integers. +// This is because the scalar coersions x|0 and x>>>0 work with any kind of +// integer input, while the SIMD check functions throw a TypeError if the passed +// type doesn't match. +// class Type { public: @@ -1071,6 +1071,7 @@ class Type DoubleLit = NumLit::Double, Float = NumLit::Float, Int32x4 = NumLit::Int32x4, + Uint32x4 = NumLit::Uint32x4, Float32x4 = NumLit::Float32x4, Bool32x4 = NumLit::Bool32x4, Double, @@ -1091,6 +1092,7 @@ class Type MOZ_IMPLICIT Type(SimdType type) { switch (type) { case SimdType::Int32x4: which_ = Int32x4; return; + case SimdType::Uint32x4: which_ = Uint32x4; return; case SimdType::Float32x4: which_ = Float32x4; return; case SimdType::Bool32x4: which_ = Bool32x4; return; default: break; @@ -1098,33 +1100,11 @@ class Type MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("bad SimdType"); } - static Type var(ValType t) { - switch (t) { - case ValType::I32: return Int; - case ValType::I64: MOZ_CRASH("no int64 in asm.js"); - case ValType::F32: return Float; - case ValType::F64: return Double; - case ValType::I32x4: return Int32x4; - case ValType::F32x4: return Float32x4; - case ValType::B32x4: return Bool32x4; - case ValType::Limit: break; - } - MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("bad type"); - } - - static Type ret(ExprType t) { - switch (t) { - case ExprType::Void: return Type::Void; - case ExprType::I32: return Signed; - case ExprType::I64: MOZ_CRASH("no int64 in asm.js"); - case ExprType::F32: return Float; - case ExprType::F64: return Double; - case ExprType::I32x4: return Int32x4; - case ExprType::F32x4: return Float32x4; - case ExprType::B32x4: return Bool32x4; - case ExprType::Limit: break; - } - MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("bad type"); + // Map an already canonicalized Type to the return type of a function call. + static Type ret(Type t) { + MOZ_ASSERT(t.isCanonical()); + // The 32-bit external type is Signed, not Int. + return t.isInt() ? Signed: t; } static Type lit(const NumLit& lit) { @@ -1136,6 +1116,43 @@ class Type return t; } + // Map |t| to one of the canonical vartype representations of a + // wasm::ExprType. + static Type canonicalize(Type t) { + switch(t.which()) { + case Fixnum: + case Signed: + case Unsigned: + case Int: + return Int; + + case Float: + return Float; + + case DoubleLit: + case Double: + return Double; + + case Void: + return Void; + + case Int32x4: + case Uint32x4: + case Float32x4: + case Bool32x4: + return t; + + case MaybeDouble: + case MaybeFloat: + case Floatish: + case Intish: + // These types need some kind of coercion, they can't be mapped + // to an ExprType. + break; + } + MOZ_CRASH("Invalid vartype"); + } + Which which() const { return which_; } bool operator==(Type rhs) const { return which_ == rhs.which_; } @@ -1149,6 +1166,7 @@ class Type case Double: return isDouble(); case Float: return isFloat(); case Int32x4: return isInt32x4(); + case Uint32x4: return isUint32x4(); case Float32x4: return isFloat32x4(); case Bool32x4: return isBool32x4(); case MaybeDouble: return isMaybeDouble(); @@ -1162,20 +1180,6 @@ class Type MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected rhs type"); } - bool operator<=(ValType rhs) const { - switch (rhs) { - case ValType::I32: return isInt(); - case ValType::I64: MOZ_CRASH("no int64 in asm.js"); - case ValType::F32: return isFloat(); - case ValType::F64: return isDouble(); - case ValType::I32x4: return isInt32x4(); - case ValType::F32x4: return isFloat32x4(); - case ValType::B32x4: return isBool32x4(); - case ValType::Limit: break; - } - MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected rhs type"); - } - bool isFixnum() const { return which_ == Fixnum; } @@ -1232,6 +1236,10 @@ class Type return which_ == Int32x4; } + bool isUint32x4() const { + return which_ == Uint32x4; + } + bool isFloat32x4() const { return which_ == Float32x4; } @@ -1241,82 +1249,66 @@ class Type } bool isSimd() const { - return isInt32x4() || isFloat32x4() || isBool32x4(); + return isInt32x4() || isUint32x4() || isFloat32x4() || isBool32x4(); } - bool isVarType() const { - return isInt() || isFloat() || isDouble() || isSimd(); + bool isUnsignedSimd() const { + return isUint32x4(); } - ValType checkedValueType() const { - MOZ_ASSERT(isVarType()); - if (isInt()) - return ValType::I32; - else if (isFloat()) - return ValType::F32; - else if (isDouble()) - return ValType::F64; - else if (isInt32x4()) - return ValType::I32x4; - else if (isBool32x4()) - return ValType::B32x4; - MOZ_ASSERT(isFloat32x4()); - return ValType::F32x4; + // Check if this is one of the valid types for a function argument. + bool isArgType() const { + return isInt() || isFloat() || isDouble() || (isSimd() && !isUnsignedSimd()); } - MIRType toMIRType() const { - switch (which_) { - case Double: - case DoubleLit: - case MaybeDouble: - return MIRType_Double; - case Float: - case Floatish: - case MaybeFloat: - return MIRType_Float32; - case Fixnum: + // Check if this is one of the valid types for a function return value. + bool isReturnType() const { + return isSigned() || isFloat() || isDouble() || (isSimd() && !isUnsignedSimd()) || + isVoid(); + } + + // Check if this is one of the valid types for a global variable. + bool isGlobalVarType() const { + return isArgType(); + } + + // Check if this is one of the canonical vartype representations of a + // wasm::ExprType. See Type::canonicalize(). + bool isCanonical() const { + switch (which()) { case Int: - case Signed: - case Unsigned: - case Intish: - return MIRType_Int32; - case Int32x4: - return MIRType_Int32x4; - case Float32x4: - return MIRType_Float32x4; - case Bool32x4: - return MIRType_Bool32x4; + case Float: + case Double: case Void: - return MIRType_None; + return true; + default: + return isSimd(); } - MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Invalid Type"); } - SimdType simdType() const { - MOZ_ASSERT(isSimd()); - switch (which_) { - case Int32x4: - return SimdType::Int32x4; - case Float32x4: - return SimdType::Float32x4; - case Bool32x4: - return SimdType::Bool32x4; - // Scalar types - case Double: - case DoubleLit: - case MaybeDouble: - case Float: - case MaybeFloat: - case Floatish: - case Fixnum: - case Int: - case Signed: - case Unsigned: - case Intish: - case Void: - break; + // Check if this is a canonical representation of a wasm::ValType. + bool isCanonicalValType() const { + return !isVoid() && isCanonical(); + } + + // Convert this canonical type to a wasm::ExprType. + ExprType canonicalToExprType() const { + switch (which()) { + case Int: return ExprType::I32; + case Float: return ExprType::F32; + case Double: return ExprType::F64; + case Void: return ExprType::Void; + case Uint32x4: + case Int32x4: return ExprType::I32x4; + case Float32x4: return ExprType::F32x4; + case Bool32x4: return ExprType::B32x4; + default: MOZ_CRASH("Need canonical type"); } - MOZ_CRASH("not a SIMD Type"); + } + + // Convert this canonical type to a wasm::ValType. + ValType canonicalToValType() const { + return NonVoidToValType(canonicalToExprType()); } const char* toChars() const { @@ -1333,6 +1325,7 @@ class Type case Unsigned: return "unsigned"; case Intish: return "intish"; case Int32x4: return "int32x4"; + case Uint32x4: return "uint32x4"; case Float32x4: return "float32x4"; case Bool32x4: return "bool32x4"; case Void: return "void"; @@ -1831,9 +1824,13 @@ class MOZ_STACK_CLASS ModuleValidator MOZ_ASSERT(n->isTenured()); module_->bufferArgumentName = n; } - bool addGlobalVarInit(PropertyName* var, const NumLit& lit, bool isConst) { + bool addGlobalVarInit(PropertyName* var, const NumLit& lit, Type type, bool isConst) + { + MOZ_ASSERT(type.isGlobalVarType()); + MOZ_ASSERT(type == Type::canonicalize(Type::lit(lit))); + uint32_t index; - if (!mg_.allocateGlobalVar(lit.type(), isConst, &index)) + if (!mg_.allocateGlobalVar(type.canonicalToValType(), isConst, &index)) return false; Global::Which which = isConst ? Global::ConstantLiteral : Global::Variable; @@ -1841,7 +1838,7 @@ class MOZ_STACK_CLASS ModuleValidator if (!global) return false; global->u.varOrConst.index_ = index; - global->u.varOrConst.type_ = (isConst ? Type::lit(lit) : Type::var(lit.type())).which(); + global->u.varOrConst.type_ = (isConst ? Type::lit(lit) : type).which(); if (isConst) global->u.varOrConst.literalValue_ = lit; if (!globalMap_.putNew(var, global)) @@ -1853,9 +1850,12 @@ class MOZ_STACK_CLASS ModuleValidator g.pod.u.var.globalDataOffset_ = mg_.globalVar(index).globalDataOffset; return module_->globals.append(g); } - bool addGlobalVarImport(PropertyName* var, PropertyName* field, ValType type, bool isConst) { + bool addGlobalVarImport(PropertyName* var, PropertyName* field, Type type, bool isConst) { + MOZ_ASSERT(type.isGlobalVarType()); + uint32_t index; - if (!mg_.allocateGlobalVar(type, isConst, &index)) + ValType valType = type.canonicalToValType(); + if (!mg_.allocateGlobalVar(valType, isConst, &index)) return false; Global::Which which = isConst ? Global::ConstantImport : Global::Variable; @@ -1863,13 +1863,13 @@ class MOZ_STACK_CLASS ModuleValidator if (!global) return false; global->u.varOrConst.index_ = index; - global->u.varOrConst.type_ = Type::var(type).which(); + global->u.varOrConst.type_ = type.which(); if (!globalMap_.putNew(var, global)) return false; AsmJSGlobal g(AsmJSGlobal::Variable, field); g.pod.u.var.initKind_ = AsmJSGlobal::InitImport; - g.pod.u.var.u.importType_ = type; + g.pod.u.var.u.importType_ = valType; g.pod.u.var.globalDataOffset_ = mg_.globalVar(index).globalDataOffset; return module_->globals.append(g); } @@ -2285,20 +2285,8 @@ IsCallToGlobal(ModuleValidator& m, ParseNode* pn, const ModuleValidator::Global* return !!*global; } -static ValType -ToValType(SimdType type) -{ - switch (type) { - case SimdType::Int32x4: return ValType::I32x4; - case SimdType::Float32x4: return ValType::F32x4; - case SimdType::Bool32x4: return ValType::B32x4; - default: break; - } - MOZ_CRASH("unexpected SIMD type"); -} - static bool -IsCoercionCall(ModuleValidator& m, ParseNode* pn, ValType* coerceTo, ParseNode** coercedExpr) +IsCoercionCall(ModuleValidator& m, ParseNode* pn, Type* coerceTo, ParseNode** coercedExpr) { const ModuleValidator::Global* global; if (!IsCallToGlobal(m, pn, &global)) @@ -2311,12 +2299,12 @@ IsCoercionCall(ModuleValidator& m, ParseNode* pn, ValType* coerceTo, ParseNode** *coercedExpr = CallArgList(pn); if (global->isMathFunction() && global->mathBuiltinFunction() == AsmJSMathBuiltin_fround) { - *coerceTo = ValType::F32; + *coerceTo = Type::Float; return true; } if (global->isSimdOperation() && global->simdOperation() == SimdOperation::Fn_check) { - *coerceTo = ToValType(global->simdOperationType()); + *coerceTo = global->simdOperationType(); return true; } @@ -2327,29 +2315,15 @@ static bool IsFloatLiteral(ModuleValidator& m, ParseNode* pn) { ParseNode* coercedExpr; - ValType coerceTo; + Type coerceTo; if (!IsCoercionCall(m, pn, &coerceTo, &coercedExpr)) return false; // Don't fold into || to avoid clang/memcheck bug (bug 1077031). - if (coerceTo != ValType::F32) + if (!coerceTo.isFloat()) return false; return IsNumericNonFloatLiteral(coercedExpr); } -static unsigned -SimdTypeToLength(SimdType type) -{ - switch (type) { - case SimdType::Int32x4: - case SimdType::Float32x4: - case SimdType::Bool32x4: - return 4; - default: - break; - } - MOZ_CRASH("unexpected SIMD type"); -} - static bool IsSimdTuple(ModuleValidator& m, ParseNode* pn, SimdType* type) { @@ -2360,7 +2334,7 @@ IsSimdTuple(ModuleValidator& m, ParseNode* pn, SimdType* type) if (!global->isSimdCtor()) return false; - if (CallArgListLength(pn) != SimdTypeToLength(global->simdCtorType())) + if (CallArgListLength(pn) != GetSimdLanes(global->simdCtorType())) return false; *type = global->simdCtorType(); @@ -2384,7 +2358,7 @@ IsSimdLiteral(ModuleValidator& m, ParseNode* pn) return false; ParseNode* arg = CallArgList(pn); - unsigned length = SimdTypeToLength(type); + unsigned length = GetSimdLanes(type); for (unsigned i = 0; i < length; i++) { if (!IsNumericLiteral(m, arg)) return false; @@ -2392,6 +2366,7 @@ IsSimdLiteral(ModuleValidator& m, ParseNode* pn) uint32_t _; switch (type) { case SimdType::Int32x4: + case SimdType::Uint32x4: case SimdType::Bool32x4: if (!IsLiteralInt(m, arg, &_)) return false; @@ -2448,8 +2423,9 @@ ExtractSimdValue(ModuleValidator& m, ParseNode* pn) ParseNode* arg = CallArgList(pn); switch (type) { - case SimdType::Int32x4: { - MOZ_ASSERT(SimdTypeToLength(type) == 4); + case SimdType::Int32x4: + case SimdType::Uint32x4: { + MOZ_ASSERT(GetSimdLanes(type) == 4); int32_t val[4]; for (size_t i = 0; i < 4; i++, arg = NextNode(arg)) { uint32_t u32; @@ -2457,10 +2433,11 @@ ExtractSimdValue(ModuleValidator& m, ParseNode* pn) val[i] = int32_t(u32); } MOZ_ASSERT(arg== nullptr); - return NumLit(NumLit::Int32x4, SimdConstant::CreateX4(val)); + NumLit::Which w = type == SimdType::Uint32x4 ? NumLit::Uint32x4 : NumLit::Int32x4; + return NumLit(w, SimdConstant::CreateX4(val)); } case SimdType::Float32x4: { - MOZ_ASSERT(SimdTypeToLength(type) == 4); + MOZ_ASSERT(GetSimdLanes(type) == 4); float val[4]; for (size_t i = 0; i < 4; i++, arg = NextNode(arg)) val[i] = float(ExtractNumericNonFloatValue(arg)); @@ -2468,7 +2445,7 @@ ExtractSimdValue(ModuleValidator& m, ParseNode* pn) return NumLit(NumLit::Float32x4, SimdConstant::CreateX4(val)); } case SimdType::Bool32x4: { - MOZ_ASSERT(SimdTypeToLength(type) == 4); + MOZ_ASSERT(GetSimdLanes(type) == 4); int32_t val[4]; for (size_t i = 0; i < 4; i++, arg = NextNode(arg)) { uint32_t u32; @@ -2547,6 +2524,7 @@ IsLiteralInt(NumLit lit, uint32_t* u32) case NumLit::Float: case NumLit::OutOfRangeInt: case NumLit::Int32x4: + case NumLit::Uint32x4: case NumLit::Float32x4: case NumLit::Bool32x4: return false; @@ -2580,7 +2558,22 @@ static inline Expr SimdToExpr(SimdType type, SimdOperation op) { switch (type) { + case SimdType::Uint32x4: + // Handle the special unsigned opcodes, then fall through to Int32x4. + switch(op) { + case SimdOperation::Fn_shiftRightByScalar: return Expr::I32x4shiftRightByScalarU; + case SimdOperation::Fn_lessThan: return Expr::I32x4lessThanU; + case SimdOperation::Fn_lessThanOrEqual: return Expr::I32x4lessThanOrEqualU; + case SimdOperation::Fn_greaterThan: return Expr::I32x4greaterThanU; + case SimdOperation::Fn_greaterThanOrEqual: return Expr::I32x4greaterThanOrEqualU; + case SimdOperation::Fn_fromFloat32x4: return Expr::I32x4fromFloat32x4U; + case SimdOperation::Fn_fromInt32x4Bits: return Expr::Id; + default: break; + } + MOZ_FALLTHROUGH; case SimdType::Int32x4: { + // Bitcasts Uint32x4 <--> Int32x4 become noops. + if (op == SimdOperation::Fn_fromUint32x4Bits) return Expr::Id; ENUMERATE(I32x4, FORALL_INT32X4_ASMJS_OP, I32CASE) break; } @@ -2611,9 +2604,11 @@ class MOZ_STACK_CLASS FunctionValidator public: struct Local { - ValType type; + Type type; unsigned slot; - Local(ValType t, unsigned slot) : type(t), slot(slot) {} + Local(Type t, unsigned slot) : type(t), slot(slot) { + MOZ_ASSERT(type.isCanonicalValType()); + } }; private: @@ -2678,12 +2673,12 @@ class MOZ_STACK_CLASS FunctionValidator /***************************************************** Local scope setup */ - bool addLocal(ParseNode* pn, PropertyName* name, ValType type) { + bool addLocal(ParseNode* pn, PropertyName* name, Type type) { LocalMap::AddPtr p = locals_.lookupForAdd(name); if (p) return failName(pn, "duplicate local name '%s' not allowed", name); return locals_.add(p, name, Local(type, locals_.count())) && - fg_.addLocal(type); + fg_.addLocal(type.canonicalToValType()); } /****************************** For consistency of returns in a function */ @@ -2757,6 +2752,7 @@ class MOZ_STACK_CLASS FunctionValidator return encoder().writeExpr(Expr::F64Const) && encoder().writeFixedF64(lit.toDouble()); case NumLit::Int32x4: + case NumLit::Uint32x4: return encoder().writeExpr(Expr::I32x4Const) && encoder().writeFixedI32x4(lit.simdValue().asInt32x4()); case NumLit::Float32x4: @@ -2907,11 +2903,15 @@ CheckGlobalVariableInitConstant(ModuleValidator& m, PropertyName* varName, Parse if (!lit.valid()) return m.fail(initNode, "global initializer is out of representable integer range"); - return m.addGlobalVarInit(varName, lit, isConst); + Type canonicalType = Type::canonicalize(Type::lit(lit)); + if (!canonicalType.isGlobalVarType()) + return m.fail(initNode, "global variable type not allowed"); + + return m.addGlobalVarInit(varName, lit, canonicalType, isConst); } static bool -CheckTypeAnnotation(ModuleValidator& m, ParseNode* coercionNode, ValType* coerceTo, +CheckTypeAnnotation(ModuleValidator& m, ParseNode* coercionNode, Type* coerceTo, ParseNode** coercedExpr = nullptr) { switch (coercionNode->getKind()) { @@ -2920,13 +2920,13 @@ CheckTypeAnnotation(ModuleValidator& m, ParseNode* coercionNode, ValType* coerce uint32_t i; if (!IsLiteralInt(m, rhs, &i) || i != 0) return m.fail(rhs, "must use |0 for argument/return coercion"); - *coerceTo = ValType::I32; + *coerceTo = Type::Int; if (coercedExpr) *coercedExpr = BitwiseLeft(coercionNode); return true; } case PNK_POS: { - *coerceTo = ValType::F64; + *coerceTo = Type::Double; if (coercedExpr) *coercedExpr = UnaryKid(coercionNode); return true; @@ -2943,12 +2943,20 @@ CheckTypeAnnotation(ModuleValidator& m, ParseNode* coercionNode, ValType* coerce } static bool -CheckGlobalVariableImportExpr(ModuleValidator& m, PropertyName* varName, ValType coerceTo, - ParseNode* coercedExpr, bool isConst) +CheckGlobalVariableInitImport(ModuleValidator& m, PropertyName* varName, ParseNode* initNode, + bool isConst) { + Type coerceTo; + ParseNode* coercedExpr; + if (!CheckTypeAnnotation(m, initNode, &coerceTo, &coercedExpr)) + return false; + if (!coercedExpr->isKind(PNK_DOT)) return m.failName(coercedExpr, "invalid import expression for global '%s'", varName); + if (!coerceTo.isGlobalVarType()) + return m.fail(initNode, "global variable type not allowed"); + ParseNode* base = DotBase(coercedExpr); PropertyName* field = DotMember(coercedExpr); @@ -2961,17 +2969,6 @@ CheckGlobalVariableImportExpr(ModuleValidator& m, PropertyName* varName, ValType return m.addGlobalVarImport(varName, field, coerceTo, isConst); } -static bool -CheckGlobalVariableInitImport(ModuleValidator& m, PropertyName* varName, ParseNode* initNode, - bool isConst) -{ - ValType coerceTo; - ParseNode* coercedExpr; - if (!CheckTypeAnnotation(m, initNode, &coerceTo, &coercedExpr)) - return false; - return CheckGlobalVariableImportExpr(m, varName, coerceTo, coercedExpr, isConst); -} - static bool IsArrayViewCtorName(ModuleValidator& m, PropertyName* name, Scalar::Type* type) { @@ -3057,24 +3054,6 @@ CheckNewArrayView(ModuleValidator& m, PropertyName* varName, ParseNode* newExpr) return m.addArrayView(varName, type, field); } -static bool -IsSimdTypeName(ModuleValidator& m, PropertyName* name, SimdType* type) -{ - if (name == m.cx()->names().Int32x4) { - *type = SimdType::Int32x4; - return true; - } - if (name == m.cx()->names().Float32x4) { - *type = SimdType::Float32x4; - return true; - } - if (name == m.cx()->names().Bool32x4) { - *type = SimdType::Bool32x4; - return true; - } - return false; -} - static bool IsSimdValidOperationType(SimdType type, SimdOperation op) { @@ -3082,27 +3061,39 @@ IsSimdValidOperationType(SimdType type, SimdOperation op) switch(type) { case SimdType::Int32x4: switch (op) { + case SimdOperation::Constructor: + case SimdOperation::Fn_fromUint32x4Bits: + FORALL_INT32X4_ASMJS_OP(CASE) return true; + default: return false; + } + break; + case SimdType::Uint32x4: + switch (op) { + case SimdOperation::Constructor: + case SimdOperation::Fn_fromInt32x4Bits: FORALL_INT32X4_ASMJS_OP(CASE) return true; default: return false; } break; case SimdType::Float32x4: switch (op) { + case SimdOperation::Constructor: FORALL_FLOAT32X4_ASMJS_OP(CASE) return true; default: return false; } break; case SimdType::Bool32x4: switch (op) { + case SimdOperation::Constructor: FORALL_BOOL_SIMD_OP(CASE) return true; default: return false; } break; default: - break; + // Unimplemented SIMD type. + return false; } #undef CASE - MOZ_CRASH("Unhandles SIMD type"); } static bool @@ -3146,8 +3137,17 @@ CheckGlobalSimdImport(ModuleValidator& m, ParseNode* initNode, PropertyName* var // SIMD constructor, with the form glob.SIMD.[[type]] SimdType simdType; - if (!IsSimdTypeName(m, field, &simdType)) + if (!IsSimdTypeName(m.cx()->names(), field, &simdType)) return m.failName(initNode, "'%s' is not a standard SIMD type", field); + + // IsSimdTypeName will return true for any SIMD type supported by the VM. + // + // Since we may not support all of those SIMD types in asm.js, use the + // asm.js-specific IsSimdValidOperationType() to check if this specific + // constructor is supported in asm.js. + if (!IsSimdValidOperationType(simdType, SimdOperation::Constructor)) + return m.failName(initNode, "'%s' is not a supported SIMD type", field); + return m.addSimdCtor(varName, simdType, field); } @@ -3300,7 +3300,7 @@ ArgFail(FunctionValidator& f, PropertyName* argName, ParseNode* stmt) } static bool -CheckArgumentType(FunctionValidator& f, ParseNode* stmt, PropertyName* name, ValType* type) +CheckArgumentType(FunctionValidator& f, ParseNode* stmt, PropertyName* name, Type* type) { if (!stmt || !IsExpressionStatement(stmt)) return ArgFail(f, name, stmt ? stmt : f.fn()); @@ -3319,6 +3319,9 @@ CheckArgumentType(FunctionValidator& f, ParseNode* stmt, PropertyName* name, Val if (!CheckTypeAnnotation(f.m(), coercionNode, type, &coercedExpr)) return false; + if (!type->isArgType()) + return f.failName(stmt, "invalid type for argument '%s'", name); + if (!IsUseOfName(coercedExpr, name)) return ArgFail(f, name, stmt); @@ -3350,11 +3353,11 @@ CheckArguments(FunctionValidator& f, ParseNode** stmtIter, ValTypeVector* argTyp if (!CheckArgument(f.m(), argpn, &name)) return false; - ValType type; + Type type; if (!CheckArgumentType(f, stmt, name, &type)) return false; - if (!argTypes->append(type)) + if (!argTypes->append(type.canonicalToValType())) return false; if (!f.addLocal(argpn, name, type)) @@ -3434,7 +3437,7 @@ CheckVariable(FunctionValidator& f, ParseNode* var, uint32_t* numStmts) return false; } - return f.addLocal(var, name, lit.type()); + return f.addLocal(var, name, Type::canonicalize(Type::lit(lit))); } static bool @@ -3474,10 +3477,9 @@ CheckVarRef(FunctionValidator& f, ParseNode* varRef, Type* type) if (const FunctionValidator::Local* local = f.lookupLocal(name)) { if (!f.encoder().writeExpr(Expr::GetLocal)) return false; - MOZ_ASSERT(local->type != ValType::I64, "no int64 in asm.js"); if (!f.encoder().writeVarU32(local->slot)) return false; - *type = Type::var(local->type); + *type = local->type; return true; } @@ -3796,9 +3798,8 @@ CheckAssignName(FunctionValidator& f, ParseNode* lhs, ParseNode* rhs, Type* type if (!(rhsType <= lhsVar->type)) { return f.failf(lhs, "%s is not a subtype of %s", - rhsType.toChars(), Type::var(lhsVar->type).toChars()); + rhsType.toChars(), lhsVar->type.toChars()); } - MOZ_ASSERT(lhsVar->type != ValType::I64, "no int64 in asm.js"); *type = rhsType; return true; } @@ -4300,7 +4301,7 @@ CheckCallArgs(FunctionValidator& f, ParseNode* callNode, ValTypeVector* args) if (!checkArg(f, argNode, type)) return false; - if (!args->append(type.checkedValueType())) + if (!args->append(Type::canonicalize(type).canonicalToValType())) return false; } return true; @@ -4316,14 +4317,14 @@ CheckSignatureAgainstExisting(ModuleValidator& m, ParseNode* usepn, const Sig& s for (unsigned i = 0; i < sig.args().length(); i++) { if (sig.arg(i) != existing.arg(i)) { - return m.failf(usepn, "incompatible type for argument %u: (%s here vs. %s before)", - i, Type::var(sig.arg(i)).toChars(), Type::var(existing.arg(i)).toChars()); + return m.failf(usepn, "incompatible type for argument %u: (%s here vs. %s before)", i, + ToCString(sig.arg(i)), ToCString(existing.arg(i))); } } if (sig.ret() != existing.ret()) { return m.failf(usepn, "%s incompatible with previous return of type %s", - Type::ret(sig.ret()).toChars(), Type::ret(existing.ret()).toChars()); + ToCString(sig.ret()), ToCString(existing.ret())); } MOZ_ASSERT(sig == existing); @@ -4349,17 +4350,22 @@ CheckFunctionSignature(ModuleValidator& m, ParseNode* usepn, Sig&& sig, Property } static bool -CheckIsVarType(FunctionValidator& f, ParseNode* argNode, Type type) +CheckIsArgType(FunctionValidator& f, ParseNode* argNode, Type type) { - if (!type.isVarType()) - return f.failf(argNode, "%s is not a subtype of int, float or double", type.toChars()); + if (!type.isArgType()) + return f.failf(argNode, + "%s is not a subtype of int, float, double, or an allowed SIMD type", + type.toChars()); + return true; } static bool CheckInternalCall(FunctionValidator& f, ParseNode* callNode, PropertyName* calleeName, - ExprType ret, Type* type) + Type ret, Type* type) { + MOZ_ASSERT(ret.isCanonical()); + if (!f.writeCall(callNode, Expr::Call)) return false; @@ -4369,11 +4375,12 @@ CheckInternalCall(FunctionValidator& f, ParseNode* callNode, PropertyName* calle return false; ValTypeVector args; - if (!CheckCallArgs(f, callNode, &args)) + if (!CheckCallArgs(f, callNode, &args)) return false; + Sig sig(Move(args), ret.canonicalToExprType()); ModuleValidator::Func* callee; - if (!CheckFunctionSignature(f.m(), callNode, Sig(Move(args), ret), calleeName, &callee)) + if (!CheckFunctionSignature(f.m(), callNode, Move(sig), calleeName, &callee)) return false; f.encoder().patchVarU32(funcIndexAt, callee->index()); @@ -4410,8 +4417,10 @@ CheckFuncPtrTableAgainstExisting(ModuleValidator& m, ParseNode* usepn, PropertyN } static bool -CheckFuncPtrCall(FunctionValidator& f, ParseNode* callNode, ExprType ret, Type* type) +CheckFuncPtrCall(FunctionValidator& f, ParseNode* callNode, Type ret, Type* type) { + MOZ_ASSERT(ret.isCanonical()); + ParseNode* callee = CallCallee(callNode); ParseNode* tableNode = ElemBase(callee); ParseNode* indexExpr = ElemIndex(callee); @@ -4452,10 +4461,10 @@ CheckFuncPtrCall(FunctionValidator& f, ParseNode* callNode, ExprType ret, Type* return f.failf(indexNode, "%s is not a subtype of intish", indexType.toChars()); ValTypeVector args; - if (!CheckCallArgs(f, callNode, &args)) + if (!CheckCallArgs(f, callNode, &args)) return false; - Sig sig(Move(args), ret); + Sig sig(Move(args), ret.canonicalToExprType()); uint32_t tableIndex; if (!CheckFuncPtrTableAgainstExisting(f.m(), tableNode, name, Move(sig), mask, &tableIndex)) @@ -4476,14 +4485,15 @@ CheckIsExternType(FunctionValidator& f, ParseNode* argNode, Type type) } static bool -CheckFFICall(FunctionValidator& f, ParseNode* callNode, unsigned ffiIndex, ExprType ret, - Type* type) +CheckFFICall(FunctionValidator& f, ParseNode* callNode, unsigned ffiIndex, Type ret, Type* type) { + MOZ_ASSERT(ret.isCanonical()); + PropertyName* calleeName = CallCallee(callNode)->name(); - if (ret == ExprType::F32) + if (ret.isFloat()) return f.fail(callNode, "FFI calls can't return float"); - if (IsSimdType(ret)) + if (ret.isSimd()) return f.fail(callNode, "FFI calls can't return SIMD values"); // Opcode @@ -4499,8 +4509,9 @@ CheckFFICall(FunctionValidator& f, ParseNode* callNode, unsigned ffiIndex, ExprT if (!CheckCallArgs(f, callNode, &args)) return false; + Sig sig(Move(args), ret.canonicalToExprType()); uint32_t importIndex; - if (!f.m().declareImport(calleeName, Sig(Move(args), ret), ffiIndex, &importIndex)) + if (!f.m().declareImport(calleeName, Move(sig), ffiIndex, &importIndex)) return false; f.encoder().patchVarU32(importIndexAt, importIndex); @@ -4535,14 +4546,15 @@ CheckFloatCoercionArg(FunctionValidator& f, ParseNode* inputNode, Type inputType } static bool -CheckCoercedCall(FunctionValidator& f, ParseNode* call, ExprType ret, Type* type); +CheckCoercedCall(FunctionValidator& f, ParseNode* call, Type ret, Type* type); static bool -CheckCoercionArg(FunctionValidator& f, ParseNode* arg, ValType expected, Type* type) +CheckCoercionArg(FunctionValidator& f, ParseNode* arg, Type expected, Type* type) { - ExprType ret = ToExprType(expected); + MOZ_ASSERT(expected.isCanonicalValType()); + if (arg->isKind(PNK_CALL)) - return CheckCoercedCall(f, arg, ret, type); + return CheckCoercedCall(f, arg, expected, type); size_t opcodeAt; if (!f.encoder().writePatchableExpr(&opcodeAt)) @@ -4552,27 +4564,18 @@ CheckCoercionArg(FunctionValidator& f, ParseNode* arg, ValType expected, Type* t if (!CheckExpr(f, arg, &argType)) return false; - switch (expected) { - case ValType::F32: + if (expected.isFloat()) { if (!CheckFloatCoercionArg(f, arg, argType, opcodeAt)) return false; - break; - case ValType::I64: - MOZ_CRASH("no int64 in asm.js"); - case ValType::I32x4: - case ValType::F32x4: - case ValType::B32x4: + } else if (expected.isSimd()) { if (!(argType <= expected)) return f.fail(arg, "argument to SIMD coercion isn't from the correct SIMD type"); f.encoder().patchExpr(opcodeAt, Expr::Id); - break; - case ValType::I32: - case ValType::F64: - case ValType::Limit: + } else { MOZ_CRASH("not call coercions"); } - *type = Type::ret(ret); + *type = Type::ret(expected); return true; } @@ -4584,7 +4587,7 @@ CheckMathFRound(FunctionValidator& f, ParseNode* callNode, Type* type) ParseNode* argNode = CallArgList(callNode); Type argType; - if (!CheckCoercionArg(f, argNode, ValType::F32, &argType)) + if (!CheckCoercionArg(f, argNode, Type::Float, &argType)) return false; MOZ_ASSERT(argType == Type::Float); @@ -4736,6 +4739,7 @@ SimdToCoercedScalarType(SimdType t) { switch (t) { case SimdType::Int32x4: + case SimdType::Uint32x4: case SimdType::Bool32x4: return Type::Intish; case SimdType::Float32x4: @@ -4859,7 +4863,7 @@ class CheckSimdExtractLaneArgs // Second argument is the lane < vector length if (!IsLiteralOrConstInt(f, arg, &laneIndex)) return f.failf(arg, "lane selector should be a constant integer literal"); - if (laneIndex >= SimdTypeToLength(formalSimdType_)) + if (laneIndex >= GetSimdLanes(formalSimdType_)) return f.failf(arg, "lane selector should be in bounds"); return true; } @@ -4890,7 +4894,7 @@ class CheckSimdReplaceLaneArgs // Second argument is the lane (< vector length). if (!IsLiteralOrConstInt(f, arg, &u32)) return f.failf(arg, "lane selector should be a constant integer literal"); - if (u32 >= SimdTypeToLength(formalSimdType_)) + if (u32 >= GetSimdLanes(formalSimdType_)) return f.failf(arg, "lane selector should be in bounds"); f.encoder().patchExpr(patchAt, Expr::Id); return true; @@ -4924,7 +4928,7 @@ CheckSimdBinaryShift(FunctionValidator& f, ParseNode* call, SimdType opType, Sim return false; if (!CheckSimdCallArgs(f, call, 2, CheckSimdVectorScalarArgs(opType))) return false; - *type = Type::Int32x4; + *type = opType; return true; } @@ -4936,7 +4940,7 @@ CheckSimdBinaryComp(FunctionValidator& f, ParseNode* call, SimdType opType, Simd return false; if (!CheckSimdCallArgs(f, call, 2, CheckArgIsSubtypeOf(opType))) return false; - *type = Type::Bool32x4; + *type = GetBooleanSimdType(opType); return true; } @@ -4959,6 +4963,7 @@ CheckSimdExtractLane(FunctionValidator& f, ParseNode* call, SimdType opType, Typ return false; switch (opType) { case SimdType::Int32x4: *type = Type::Signed; break; + case SimdType::Uint32x4: *type = Type::Unsigned; break; case SimdType::Float32x4: *type = Type::Float; break; case SimdType::Bool32x4: *type = Type::Int; break; default: MOZ_CRASH("unhandled simd type"); @@ -5191,7 +5196,7 @@ CheckSimdAnyTrue(FunctionValidator& f, ParseNode* call, SimdType opType, Type* t static bool CheckSimdCheck(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type) { - ValType coerceTo; + Type coerceTo; ParseNode* argNode; if (!IsCoercionCall(f.m(), call, &coerceTo, &argNode)) return f.failf(call, "expected 1 argument in call to check"); @@ -5242,6 +5247,9 @@ CheckSimdOperationCall(FunctionValidator& f, ParseNode* call, const ModuleValida case SimdOperation::Fn_fromInt32x4: case SimdOperation::Fn_fromInt32x4Bits: return CheckSimdCast(f, call, SimdType::Int32x4, opType, op, type); + case SimdOperation::Fn_fromUint32x4: + case SimdOperation::Fn_fromUint32x4Bits: + return CheckSimdCast(f, call, SimdType::Uint32x4, opType, op, type); case SimdOperation::Fn_fromFloat32x4: case SimdOperation::Fn_fromFloat32x4Bits: return CheckSimdCast(f, call, SimdType::Float32x4, opType, op, type); @@ -5283,12 +5291,10 @@ CheckSimdOperationCall(FunctionValidator& f, ParseNode* call, const ModuleValida case SimdOperation::Constructor: MOZ_CRASH("constructors are handled in CheckSimdCtorCall"); - case SimdOperation::Fn_fromUint32x4: case SimdOperation::Fn_fromInt8x16Bits: case SimdOperation::Fn_fromInt16x8Bits: case SimdOperation::Fn_fromUint8x16Bits: case SimdOperation::Fn_fromUint16x8Bits: - case SimdOperation::Fn_fromUint32x4Bits: case SimdOperation::Fn_fromFloat64x2Bits: MOZ_CRASH("NYI"); } @@ -5305,7 +5311,7 @@ CheckSimdCtorCall(FunctionValidator& f, ParseNode* call, const ModuleValidator:: if (!f.writeSimdOp(simdType, SimdOperation::Constructor)) return false; - unsigned length = SimdTypeToLength(simdType); + unsigned length = GetSimdLanes(simdType); if (!CheckSimdCallArgsPatchable(f, call, length, CheckSimdScalarArgs(simdType))) return false; @@ -5337,27 +5343,27 @@ CheckUncoercedCall(FunctionValidator& f, ParseNode* expr, Type* type) } static bool -CoerceResult(FunctionValidator& f, ParseNode* expr, ExprType expected, Type actual, size_t patchAt, +CoerceResult(FunctionValidator& f, ParseNode* expr, Type expected, Type actual, size_t patchAt, Type* type) { + MOZ_ASSERT(expected.isCanonical()); + // At this point, the bytecode resembles this: // | patchAt | the thing we wanted to coerce | current position |> - switch (expected) { - case ExprType::Void: + switch (expected.which()) { + case Type::Void: f.encoder().patchExpr(patchAt, Expr::Id); break; - case ExprType::I32: + case Type::Int: if (!actual.isIntish()) return f.failf(expr, "%s is not a subtype of intish", actual.toChars()); f.encoder().patchExpr(patchAt, Expr::Id); break; - case ExprType::I64: - MOZ_CRASH("no int64 in asm.js"); - case ExprType::F32: + case Type::Float: if (!CheckFloatCoercionArg(f, expr, actual, patchAt)) return false; break; - case ExprType::F64: + case Type::Double: if (actual.isMaybeDouble()) f.encoder().patchExpr(patchAt, Expr::Id); else if (actual.isMaybeFloat()) @@ -5369,23 +5375,12 @@ CoerceResult(FunctionValidator& f, ParseNode* expr, ExprType expected, Type actu else return f.failf(expr, "%s is not a subtype of double?, float?, signed or unsigned", actual.toChars()); break; - case ExprType::I32x4: - if (!actual.isInt32x4()) - return f.failf(expr, "%s is not a subtype of int32x4", actual.toChars()); + default: + MOZ_ASSERT(expected.isSimd(), "Incomplete switch"); + if (actual != expected) + return f.failf(expr, "got type %s, expected %s", actual.toChars(), expected.toChars()); f.encoder().patchExpr(patchAt, Expr::Id); break; - case ExprType::F32x4: - if (!actual.isFloat32x4()) - return f.failf(expr, "%s is not a subtype of float32x4", actual.toChars()); - f.encoder().patchExpr(patchAt, Expr::Id); - break; - case ExprType::B32x4: - if (!actual.isBool32x4()) - return f.failf(expr, "%s is not a subtype of bool32x4", actual.toChars()); - f.encoder().patchExpr(patchAt, Expr::Id); - break; - case ExprType::Limit: - MOZ_CRASH("Limit"); } *type = Type::ret(expected); @@ -5394,7 +5389,7 @@ CoerceResult(FunctionValidator& f, ParseNode* expr, ExprType expected, Type actu static bool CheckCoercedMathBuiltinCall(FunctionValidator& f, ParseNode* callNode, AsmJSMathBuiltinFunction func, - ExprType ret, Type* type) + Type ret, Type* type) { size_t opcodeAt; if (!f.encoder().writePatchableExpr(&opcodeAt)) @@ -5407,8 +5402,10 @@ CheckCoercedMathBuiltinCall(FunctionValidator& f, ParseNode* callNode, AsmJSMath static bool CheckCoercedSimdCall(FunctionValidator& f, ParseNode* call, const ModuleValidator::Global* global, - ExprType ret, Type* type) + Type ret, Type* type) { + MOZ_ASSERT(ret.isCanonical()); + size_t opcodeAt; if (!f.encoder().writePatchableExpr(&opcodeAt)) return false; @@ -5429,8 +5426,10 @@ CheckCoercedSimdCall(FunctionValidator& f, ParseNode* call, const ModuleValidato static bool CheckCoercedAtomicsBuiltinCall(FunctionValidator& f, ParseNode* callNode, - AsmJSAtomicsBuiltinFunction func, ExprType ret, Type* type) + AsmJSAtomicsBuiltinFunction func, Type ret, Type* type) { + MOZ_ASSERT(ret.isCanonical()); + size_t opcodeAt; if (!f.encoder().writePatchableExpr(&opcodeAt)) return false; @@ -5441,8 +5440,10 @@ CheckCoercedAtomicsBuiltinCall(FunctionValidator& f, ParseNode* callNode, } static bool -CheckCoercedCall(FunctionValidator& f, ParseNode* call, ExprType ret, Type* type) +CheckCoercedCall(FunctionValidator& f, ParseNode* call, Type ret, Type* type) { + MOZ_ASSERT(ret.isCanonical()); + JS_CHECK_RECURSION_DONT_REPORT(f.cx(), return f.m().failOverRecursed()); if (IsNumericLiteral(f.m(), call)) { @@ -5498,7 +5499,7 @@ CheckPos(FunctionValidator& f, ParseNode* pos, Type* type) ParseNode* operand = UnaryKid(pos); if (operand->isKind(PNK_CALL)) - return CheckCoercedCall(f, operand, ExprType::F64, type); + return CheckCoercedCall(f, operand, Type::Double, type); size_t opcodeAt; if (!f.encoder().writePatchableExpr(&opcodeAt)) @@ -5508,7 +5509,7 @@ CheckPos(FunctionValidator& f, ParseNode* pos, Type* type) if (!CheckExpr(f, operand, &actual)) return false; - return CoerceResult(f, operand, ExprType::F64, actual, opcodeAt, type); + return CoerceResult(f, operand, Type::Double, actual, opcodeAt, type); } static bool @@ -5674,12 +5675,8 @@ CheckConditional(FunctionValidator& f, ParseNode* ternary, Type* type) *type = Type::Double; } else if (thenType.isFloat() && elseType.isFloat()) { *type = Type::Float; - } else if (elseType.isInt32x4() && thenType.isInt32x4()) { - *type = Type::Int32x4; - } else if (elseType.isFloat32x4() && thenType.isFloat32x4()) { - *type = Type::Float32x4; - } else if (elseType.isBool32x4() && thenType.isBool32x4()) { - *type = Type::Bool32x4; + } else if (thenType.isSimd() && elseType == thenType) { + *type = thenType; } else { return f.failf(ternary, "then/else branches of conditional must both produce int, float, " "double or SIMD types, current types are %s and %s", @@ -5707,6 +5704,7 @@ IsValidIntMultiplyConstant(ModuleValidator& m, ParseNode* expr) case NumLit::Float: case NumLit::OutOfRangeInt: case NumLit::Int32x4: + case NumLit::Uint32x4: case NumLit::Float32x4: case NumLit::Bool32x4: return false; @@ -5975,7 +5973,7 @@ CheckBitwise(FunctionValidator& f, ParseNode* bitwise, Type* type) if (IsLiteralInt(f.m(), rhs, &i) && i == uint32_t(identityElement)) { if (bitwise->isKind(PNK_BITOR) && lhs->isKind(PNK_CALL)) - return CheckCoercedCall(f, lhs, ExprType::I32, type); + return CheckCoercedCall(f, lhs, Type::Int, type); Type lhsType; if (!CheckExpr(f, lhs, &lhsType)) @@ -6066,7 +6064,7 @@ CheckAsExprStatement(FunctionValidator& f, ParseNode* expr) { Type ignored; if (expr->isKind(PNK_CALL)) - return CheckCoercedCall(f, expr, ExprType::Void, &ignored); + return CheckCoercedCall(f, expr, Type::Void, &ignored); return CheckExpr(f, expr, &ignored); } @@ -6248,6 +6246,7 @@ CheckCaseExpr(FunctionValidator& f, ParseNode* caseExpr, int32_t* value) case NumLit::Double: case NumLit::Float: case NumLit::Int32x4: + case NumLit::Uint32x4: case NumLit::Float32x4: case NumLit::Bool32x4: return f.fail(caseExpr, "switch case expression must be an integer literal"); @@ -6399,16 +6398,16 @@ CheckSwitch(FunctionValidator& f, ParseNode* switchStmt) } static bool -CheckReturnType(FunctionValidator& f, ParseNode* usepn, ExprType ret) +CheckReturnType(FunctionValidator& f, ParseNode* usepn, Type ret) { if (!f.hasAlreadyReturned()) { - f.setReturnedType(ret); + f.setReturnedType(ret.canonicalToExprType()); return true; } - if (f.returnedType() != ret) { + if (f.returnedType() != ret.canonicalToExprType()) { return f.failf(usepn, "%s incompatible with previous return of type %s", - Type::ret(ret).toChars(), Type::ret(f.returnedType()).toChars()); + Type::ret(ret).toChars(), ToCString(f.returnedType())); } return true; @@ -6423,31 +6422,16 @@ CheckReturn(FunctionValidator& f, ParseNode* returnStmt) return false; if (!expr) - return CheckReturnType(f, returnStmt, ExprType::Void); + return CheckReturnType(f, returnStmt, Type::Void); Type type; if (!CheckExpr(f, expr, &type)) return false; - ExprType ret; - if (type.isSigned()) - ret = ExprType::I32; - else if (type.isFloat()) - ret = ExprType::F32; - else if (type.isDouble()) - ret = ExprType::F64; - else if (type.isInt32x4()) - ret = ExprType::I32x4; - else if (type.isFloat32x4()) - ret = ExprType::F32x4; - else if (type.isBool32x4()) - ret = ExprType::B32x4; - else if (type.isVoid()) - ret = ExprType::Void; - else + if (!type.isReturnType()) return f.failf(expr, "%s is not a valid return type", type.toChars()); - return CheckReturnType(f, expr, ret); + return CheckReturnType(f, expr, Type::canonicalize(type)); } static bool @@ -6936,6 +6920,7 @@ GetDataProperty(JSContext* cx, HandleValue objVal, HandlePropertyName field, Mut static bool HasPureCoercion(JSContext* cx, HandleValue v) { + // Unsigned SIMD types are not allowed in function signatures. if (IsVectorObject(v) || IsVectorObject(v) || IsVectorObject(v)) return true; @@ -7136,7 +7121,7 @@ ValidateSimdType(JSContext* cx, const AsmJSGlobal& global, HandleValue globalVal else type = global.simdOperationType(); - RootedPropertyName simdTypeName(cx, SimdTypeToName(cx, type)); + RootedPropertyName simdTypeName(cx, SimdTypeToName(cx->names(), type)); if (!GetDataProperty(cx, v, simdTypeName, &v)) return false; @@ -7176,12 +7161,21 @@ ValidateSimdOperation(JSContext* cx, const AsmJSGlobal& global, HandleValue glob Native native = nullptr; switch (global.simdOperationType()) { #define SET_NATIVE_INT32X4(op) case SimdOperation::Fn_##op: native = simd_int32x4_##op; break; +#define SET_NATIVE_UINT32X4(op) case SimdOperation::Fn_##op: native = simd_uint32x4_##op; break; #define SET_NATIVE_FLOAT32X4(op) case SimdOperation::Fn_##op: native = simd_float32x4_##op; break; #define SET_NATIVE_BOOL32X4(op) case SimdOperation::Fn_##op: native = simd_bool32x4_##op; break; #define FALLTHROUGH(op) case SimdOperation::Fn_##op: case SimdType::Int32x4: switch (global.simdOperation()) { FORALL_INT32X4_ASMJS_OP(SET_NATIVE_INT32X4) + SET_NATIVE_INT32X4(fromUint32x4Bits) + default: MOZ_CRASH("shouldn't have been validated in the first place"); + } + break; + case SimdType::Uint32x4: + switch (global.simdOperation()) { + FORALL_INT32X4_ASMJS_OP(SET_NATIVE_UINT32X4) + SET_NATIVE_UINT32X4(fromInt32x4Bits) default: MOZ_CRASH("shouldn't have been validated in the first place"); } break; @@ -7199,8 +7193,9 @@ ValidateSimdOperation(JSContext* cx, const AsmJSGlobal& global, HandleValue glob break; default: MOZ_CRASH("unhandled simd type"); #undef FALLTHROUGH -#undef SET_NATIVE_FLOAT32X4 #undef SET_NATIVE_INT32X4 +#undef SET_NATIVE_UINT32X4 +#undef SET_NATIVE_FLOAT32X4 #undef SET_NATIVE_BOOL32X4 #undef SET_NATIVE } diff --git a/js/src/asmjs/Wasm.cpp b/js/src/asmjs/Wasm.cpp index 01de9c73026b..6d08a30298a0 100644 --- a/js/src/asmjs/Wasm.cpp +++ b/js/src/asmjs/Wasm.cpp @@ -83,23 +83,6 @@ class FunctionDecoder } }; -static const char* -ToCString(ExprType type) -{ - switch (type) { - case ExprType::Void: return "void"; - case ExprType::I32: return "i32"; - case ExprType::I64: return "i64"; - case ExprType::F32: return "f32"; - case ExprType::F64: return "f64"; - case ExprType::I32x4: return "i32x4"; - case ExprType::F32x4: return "f32x4"; - case ExprType::B32x4: return "b32x4"; - case ExprType::Limit:; - } - MOZ_CRASH("bad expression type"); -} - static bool CheckType(FunctionDecoder& f, ExprType actual, ExprType expected) { diff --git a/js/src/asmjs/WasmBinary.h b/js/src/asmjs/WasmBinary.h index 091850c3cd85..31b80806d731 100644 --- a/js/src/asmjs/WasmBinary.h +++ b/js/src/asmjs/WasmBinary.h @@ -273,6 +273,15 @@ enum class Expr : uint16_t I32x4Constructor, I32x4Const, #undef _ + // Unsigned I32x4 operations. These are the SIMD.Uint32x4 operations that + // behave differently from their SIMD.Int32x4 counterparts. + I32x4shiftRightByScalarU, + I32x4lessThanU, + I32x4lessThanOrEqualU, + I32x4greaterThanU, + I32x4greaterThanOrEqualU, + I32x4fromFloat32x4U, + #define _(OP) SIMD_OPCODE(F32x4, OP) FORALL_FLOAT32X4_ASMJS_OP(_) F32x4Constructor, @@ -704,19 +713,29 @@ class Decoder double uncheckedReadFixedF64() { return uncheckedRead(); } - uint32_t uncheckedReadVarU32() { - uint32_t decoded = 0; + template + UInt uncheckedReadVarU() { + static const unsigned numBits = sizeof(UInt) * CHAR_BIT; + static const unsigned remainderBits = numBits % 7; + static const unsigned numBitsInSevens = numBits - remainderBits; + UInt decoded = 0; uint32_t shift = 0; do { uint8_t byte = *cur_++; if (!(byte & 0x80)) - return decoded | (uint32_t(byte) << shift); - decoded |= uint32_t(byte & 0x7f) << shift; + return decoded | (UInt(byte) << shift); + decoded |= UInt(byte & 0x7f) << shift; shift += 7; - } while (shift != 28); + } while (shift != numBitsInSevens); uint8_t byte = *cur_++; MOZ_ASSERT(!(byte & 0xf0)); - return decoded | (uint32_t(byte) << 28); + return decoded | (UInt(byte) << numBitsInSevens); + } + uint32_t uncheckedReadVarU32() { + return uncheckedReadVarU(); + } + uint64_t uncheckedReadVarU64() { + return uncheckedReadVarU(); } Expr uncheckedReadExpr() { return uncheckedReadEnum(); diff --git a/js/src/asmjs/WasmIonCompile.cpp b/js/src/asmjs/WasmIonCompile.cpp index 037aefd68fe6..2fe95541b5b1 100644 --- a/js/src/asmjs/WasmIonCompile.cpp +++ b/js/src/asmjs/WasmIonCompile.cpp @@ -198,6 +198,15 @@ class FunctionCompiler return constant; } + MDefinition* constant(int64_t i) + { + if (inDeadCode()) + return nullptr; + MConstant* constant = MConstant::NewInt64(alloc(), i); + curBlock_->add(constant); + return constant; + } + template MDefinition* unary(MDefinition* op) { @@ -244,7 +253,7 @@ class FunctionCompiler return nullptr; MOZ_ASSERT(IsSimdType(input->type()) && input->type() == type); - MInstruction* ins = MSimdUnaryArith::NewAsmJS(alloc(), input, op); + MInstruction* ins = MSimdUnaryArith::New(alloc(), input, op); curBlock_->add(ins); return ins; } @@ -257,7 +266,7 @@ class FunctionCompiler MOZ_ASSERT(IsSimdType(lhs->type()) && rhs->type() == lhs->type()); MOZ_ASSERT(lhs->type() == type); - MSimdBinaryArith* ins = MSimdBinaryArith::NewAsmJS(alloc(), lhs, rhs, op); + auto* ins = MSimdBinaryArith::New(alloc(), lhs, rhs, op); curBlock_->add(ins); return ins; } @@ -270,18 +279,27 @@ class FunctionCompiler MOZ_ASSERT(IsSimdType(lhs->type()) && rhs->type() == lhs->type()); MOZ_ASSERT(lhs->type() == type); - MSimdBinaryBitwise* ins = MSimdBinaryBitwise::NewAsmJS(alloc(), lhs, rhs, op); + auto* ins = MSimdBinaryBitwise::New(alloc(), lhs, rhs, op); curBlock_->add(ins); return ins; } + MDefinition* binarySimdComp(MDefinition* lhs, MDefinition* rhs, MSimdBinaryComp::Operation op, + SimdSign sign) + { + if (inDeadCode()) + return nullptr; + + return MSimdBinaryComp::AddLegalized(alloc(), curBlock_, lhs, rhs, op, sign); + } + template MDefinition* binarySimd(MDefinition* lhs, MDefinition* rhs, typename T::Operation op) { if (inDeadCode()) return nullptr; - T* ins = T::NewAsmJS(alloc(), lhs, rhs, op); + T* ins = T::New(alloc(), lhs, rhs, op); curBlock_->add(ins); return ins; } @@ -316,8 +334,8 @@ class FunctionCompiler return nullptr; MOZ_ASSERT(IsSimdType(vec->type()) && vec->type() == type); - MOZ_ASSERT(!IsSimdType(val->type())); - MSimdInsertElement* ins = MSimdInsertElement::NewAsmJS(alloc(), vec, val, lane); + MOZ_ASSERT(SimdTypeToLaneArgumentType(vec->type()) == val->type()); + MSimdInsertElement* ins = MSimdInsertElement::New(alloc(), vec, val, lane); curBlock_->add(ins); return ins; } @@ -330,7 +348,7 @@ class FunctionCompiler MOZ_ASSERT(IsSimdType(mask->type())); MOZ_ASSERT(IsSimdType(lhs->type()) && rhs->type() == lhs->type()); MOZ_ASSERT(lhs->type() == type); - MSimdSelect* ins = MSimdSelect::NewAsmJS(alloc(), mask, lhs, rhs); + MSimdSelect* ins = MSimdSelect::New(alloc(), mask, lhs, rhs); curBlock_->add(ins); return ins; } @@ -340,7 +358,7 @@ class FunctionCompiler if (inDeadCode()) return nullptr; - MSimdAllTrue* ins = MSimdAllTrue::NewAsmJS(alloc(), boolVector); + MSimdAllTrue* ins = MSimdAllTrue::New(alloc(), boolVector, MIRType_Int32); curBlock_->add(ins); return ins; } @@ -350,31 +368,42 @@ class FunctionCompiler if (inDeadCode()) return nullptr; - MSimdAnyTrue* ins = MSimdAnyTrue::NewAsmJS(alloc(), boolVector); + MSimdAnyTrue* ins = MSimdAnyTrue::New(alloc(), boolVector, MIRType_Int32); curBlock_->add(ins); return ins; } - template - MDefinition* convertSimd(MDefinition* vec, MIRType from, MIRType to) + // fromXXXBits() + MDefinition* bitcastSimd(MDefinition* vec, MIRType from, MIRType to) { if (inDeadCode()) return nullptr; MOZ_ASSERT(vec->type() == from); MOZ_ASSERT(IsSimdType(from) && IsSimdType(to) && from != to); - T* ins = T::NewAsmJS(alloc(), vec, to); + auto* ins = MSimdReinterpretCast::New(alloc(), vec, to); curBlock_->add(ins); return ins; } + // Int <--> Float conversions. + MDefinition* convertSimd(MDefinition* vec, MIRType from, MIRType to, SimdSign sign) + { + if (inDeadCode()) + return nullptr; + + MOZ_ASSERT(IsSimdType(from) && IsSimdType(to) && from != to); + return MSimdConvert::AddLegalized(alloc(), curBlock_, vec, to, sign); + } + MDefinition* splatSimd(MDefinition* v, MIRType type) { if (inDeadCode()) return nullptr; MOZ_ASSERT(IsSimdType(type)); - MSimdSplatX4* ins = MSimdSplatX4::NewAsmJS(alloc(), v, type); + MOZ_ASSERT(SimdTypeToLaneArgumentType(type) == v->type()); + MSimdSplatX4* ins = MSimdSplatX4::New(alloc(), v, type); curBlock_->add(ins); return ins; } @@ -608,14 +637,14 @@ class FunctionCompiler curBlock_->add(MAsmJSInterruptCheck::New(alloc())); } - MDefinition* extractSimdElement(SimdLane lane, MDefinition* base, MIRType type) + MDefinition* extractSimdElement(SimdLane lane, MDefinition* base, MIRType type, SimdSign sign) { if (inDeadCode()) return nullptr; MOZ_ASSERT(IsSimdType(base->type())); MOZ_ASSERT(!IsSimdType(type)); - MSimdExtractElement* ins = MSimdExtractElement::NewAsmJS(alloc(), base, type, lane); + auto* ins = MSimdExtractElement::New(alloc(), base, type, lane, sign); curBlock_->add(ins); return ins; } @@ -628,7 +657,7 @@ class FunctionCompiler return nullptr; MOZ_ASSERT(IsSimdType(type)); - T* ins = T::NewAsmJS(alloc(), type, x, y, z, w); + T* ins = T::New(alloc(), type, x, y, z, w); curBlock_->add(ins); return ins; } @@ -1214,6 +1243,7 @@ class FunctionCompiler uint8_t readU8() { return decoder_.uncheckedReadFixedU8(); } uint32_t readVarU32() { return decoder_.uncheckedReadVarU32(); } + uint64_t readVarU64() { return decoder_.uncheckedReadVarU64(); } float readF32() { return decoder_.uncheckedReadFixedF32(); } double readF64() { return decoder_.uncheckedReadFixedF64(); } Expr readExpr() { return decoder_.uncheckedReadExpr(); } @@ -1344,7 +1374,9 @@ EmitLiteral(FunctionCompiler& f, ExprType type, MDefinition** def) return true; } case ExprType::I64: { - MOZ_CRASH("int64"); + int64_t val = f.readVarU64(); + *def = f.constant(val); + return true; } case ExprType::F32: { float val = f.readF32(); @@ -1773,7 +1805,7 @@ EmitSimdBinary(FunctionCompiler& f, ExprType type, OpKind op, MDefinition** def) static bool EmitSimdBinaryComp(FunctionCompiler& f, ExprType type, MSimdBinaryComp::Operation op, - MDefinition** def) + SimdSign sign, MDefinition** def) { MDefinition* lhs; if (!EmitExpr(f, type, &lhs)) @@ -1781,7 +1813,7 @@ EmitSimdBinaryComp(FunctionCompiler& f, ExprType type, MSimdBinaryComp::Operatio MDefinition* rhs; if (!EmitExpr(f, type, &rhs)) return false; - *def = f.binarySimd(lhs, rhs, op); + *def = f.binarySimdComp(lhs, rhs, op, sign); return true; } @@ -1816,7 +1848,7 @@ SimdToLaneType(ExprType type) } static bool -EmitExtractLane(FunctionCompiler& f, ExprType type, MDefinition** def) +EmitExtractLane(FunctionCompiler& f, ExprType type, SimdSign sign, MDefinition** def) { MDefinition* vec; if (!EmitExpr(f, type, &vec)) @@ -1836,7 +1868,7 @@ EmitExtractLane(FunctionCompiler& f, ExprType type, MDefinition** def) MOZ_ASSERT(laneLit < 4); SimdLane lane = SimdLane(laneLit); - *def = f.extractSimdElement(lane, vec, ToMIRType(SimdToLaneType(type))); + *def = f.extractSimdElement(lane, vec, ToMIRType(SimdToLaneType(type)), sign); return true; } @@ -1885,14 +1917,24 @@ EmitSimdReplaceLane(FunctionCompiler& f, ExprType simdType, MDefinition** def) return true; } -template inline bool -EmitSimdCast(FunctionCompiler& f, ExprType fromType, ExprType toType, MDefinition** def) +EmitSimdBitcast(FunctionCompiler& f, ExprType fromType, ExprType toType, MDefinition** def) { MDefinition* in; if (!EmitExpr(f, fromType, &in)) return false; - *def = f.convertSimd(in, ToMIRType(fromType), ToMIRType(toType)); + *def = f.bitcastSimd(in, ToMIRType(fromType), ToMIRType(toType)); + return true; +} + +inline bool +EmitSimdConvert(FunctionCompiler& f, ExprType fromType, ExprType toType, SimdSign sign, + MDefinition** def) +{ + MDefinition* in; + if (!EmitExpr(f, fromType, &in)) + return false; + *def = f.convertSimd(in, ToMIRType(fromType), ToMIRType(toType), sign); return true; } @@ -2273,13 +2315,13 @@ EmitBitwise(FunctionCompiler& f, MDefinition** def) } static bool -EmitSimdOp(FunctionCompiler& f, ExprType type, SimdOperation op, MDefinition** def) +EmitSimdOp(FunctionCompiler& f, ExprType type, SimdOperation op, SimdSign sign, MDefinition** def) { switch (op) { case SimdOperation::Constructor: return EmitSimdCtor(f, type, def); case SimdOperation::Fn_extractLane: - return EmitExtractLane(f, type, def); + return EmitExtractLane(f, type, sign, def); case SimdOperation::Fn_replaceLane: return EmitSimdReplaceLane(f, type, def); case SimdOperation::Fn_check: @@ -2322,16 +2364,10 @@ EmitSimdOp(FunctionCompiler& f, ExprType type, SimdOperation op, MDefinition** d case SimdOperation::Fn_shiftLeftByScalar: return EmitSimdShift(f, type, MSimdShift::lsh, def); case SimdOperation::Fn_shiftRightByScalar: - return EmitSimdShift(f, type, - type == ExprType::I32x4 ? MSimdShift::rsh : MSimdShift::ursh, - def); - case SimdOperation::Fn_shiftRightArithmeticByScalar: - return EmitSimdShift(f, type, MSimdShift::rsh, def); - case SimdOperation::Fn_shiftRightLogicalByScalar: - return EmitSimdShift(f, type, MSimdShift::ursh, def); + return EmitSimdShift(f, type, MSimdShift::rshForSign(sign), def); #define _CASE(OP) \ case SimdOperation::Fn_##OP: \ - return EmitSimdBinaryComp(f, type, MSimdBinaryComp::OP, def); + return EmitSimdBinaryComp(f, type, MSimdBinaryComp::OP, sign, def); FOREACH_COMP_SIMD_OP(_CASE) #undef _CASE case SimdOperation::Fn_and: @@ -2347,19 +2383,20 @@ EmitSimdOp(FunctionCompiler& f, ExprType type, SimdOperation op, MDefinition** d FOREACH_FLOAT_SIMD_BINOP(_CASE) #undef _CASE case SimdOperation::Fn_fromFloat32x4: - return EmitSimdCast(f, ExprType::F32x4, type, def); + return EmitSimdConvert(f, ExprType::F32x4, type, sign, def); case SimdOperation::Fn_fromInt32x4: - return EmitSimdCast(f, ExprType::I32x4, type, def); - case SimdOperation::Fn_fromInt32x4Bits: - return EmitSimdCast(f, ExprType::I32x4, type, def); - case SimdOperation::Fn_fromFloat32x4Bits: - return EmitSimdCast(f, ExprType::F32x4, type, def); + return EmitSimdConvert(f, ExprType::I32x4, type, SimdSign::Signed, def); case SimdOperation::Fn_fromUint32x4: + return EmitSimdConvert(f, ExprType::I32x4, type, SimdSign::Unsigned, def); + case SimdOperation::Fn_fromInt32x4Bits: + case SimdOperation::Fn_fromUint32x4Bits: + return EmitSimdBitcast(f, ExprType::I32x4, type, def); + case SimdOperation::Fn_fromFloat32x4Bits: + return EmitSimdBitcast(f, ExprType::F32x4, type, def); case SimdOperation::Fn_fromInt8x16Bits: case SimdOperation::Fn_fromInt16x8Bits: case SimdOperation::Fn_fromUint8x16Bits: case SimdOperation::Fn_fromUint16x8Bits: - case SimdOperation::Fn_fromUint32x4Bits: case SimdOperation::Fn_fromFloat64x2Bits: MOZ_CRASH("NYI"); } @@ -2808,6 +2845,9 @@ EmitExpr(FunctionCompiler& f, ExprType type, MDefinition** def, LabelVector* may return EmitAtomicsStore(f, def); case Expr::I32AtomicsBinOp: return EmitAtomicsBinOp(f, def); + // I64 + case Expr::I64Const: + return EmitLiteral(f, ExprType::I64, def); // F32 case Expr::F32Const: return EmitLiteral(f, ExprType::F32, def); @@ -2893,17 +2933,18 @@ EmitExpr(FunctionCompiler& f, ExprType type, MDefinition** def, LabelVector* may case Expr::F64StoreMemF32: return EmitStoreWithCoercion(f, Scalar::Float64, Scalar::Float32, def); // SIMD -#define CASE(TYPE, OP) \ +#define CASE(TYPE, OP, SIGN) \ case Expr::TYPE##OP: \ - return EmitSimdOp(f, ExprType::TYPE, SimdOperation::Fn_##OP, def); -#define I32CASE(OP) CASE(I32x4, OP) -#define F32CASE(OP) CASE(F32x4, OP) -#define B32CASE(OP) CASE(B32x4, OP) + return EmitSimdOp(f, ExprType::TYPE, SimdOperation::Fn_##OP, SIGN, def); +#define I32CASE(OP) CASE(I32x4, OP, SimdSign::Signed) +#define F32CASE(OP) CASE(F32x4, OP, SimdSign::NotApplicable) +#define B32CASE(OP) CASE(B32x4, OP, SimdSign::NotApplicable) #define ENUMERATE(TYPE, FORALL, DO) \ case Expr::TYPE##Const: \ return EmitLiteral(f, ExprType::TYPE, def); \ case Expr::TYPE##Constructor: \ - return EmitSimdOp(f, ExprType::TYPE, SimdOperation::Constructor, def); \ + return EmitSimdOp(f, ExprType::TYPE, SimdOperation::Constructor, \ + SimdSign::NotApplicable, def); \ FORALL(DO) ENUMERATE(I32x4, FORALL_INT32X4_ASMJS_OP, I32CASE) @@ -2915,6 +2956,25 @@ EmitExpr(FunctionCompiler& f, ExprType type, MDefinition** def, LabelVector* may #undef F32CASE #undef B32CASE #undef ENUMERATE + // SIMD unsigned integer operations. + case Expr::I32x4shiftRightByScalarU: + return EmitSimdOp(f, ExprType::I32x4, SimdOperation::Fn_shiftRightByScalar, + SimdSign::Unsigned, def); + case Expr::I32x4lessThanU: + return EmitSimdOp(f, ExprType::I32x4, SimdOperation::Fn_lessThan, SimdSign::Unsigned, def); + case Expr::I32x4lessThanOrEqualU: + return EmitSimdOp(f, ExprType::I32x4, SimdOperation::Fn_lessThanOrEqual, + SimdSign::Unsigned, def); + case Expr::I32x4greaterThanU: + return EmitSimdOp(f, ExprType::I32x4, SimdOperation::Fn_greaterThan, SimdSign::Unsigned, + def); + case Expr::I32x4greaterThanOrEqualU: + return EmitSimdOp(f, ExprType::I32x4, SimdOperation::Fn_greaterThanOrEqual, + SimdSign::Unsigned, def); + case Expr::I32x4fromFloat32x4U: + return EmitSimdOp(f, ExprType::I32x4, SimdOperation::Fn_fromFloat32x4, + SimdSign::Unsigned, def); + // Future opcodes case Expr::Loop: case Expr::Select: @@ -2929,7 +2989,6 @@ EmitExpr(FunctionCompiler& f, ExprType type, MDefinition** def, LabelVector* may case Expr::F64Nearest: case Expr::F64Trunc: case Expr::I32WrapI64: - case Expr::I64Const: case Expr::I64ExtendSI32: case Expr::I64ExtendUI32: case Expr::I64TruncSF32: diff --git a/js/src/asmjs/WasmModule.cpp b/js/src/asmjs/WasmModule.cpp index 917f9f678ad9..3c1c83b49d9c 100644 --- a/js/src/asmjs/WasmModule.cpp +++ b/js/src/asmjs/WasmModule.cpp @@ -231,14 +231,9 @@ StaticLinkData::clone(JSContext* cx, StaticLinkData* out) const size_t StaticLinkData::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const { - size_t size = internalLinks.sizeOfExcludingThis(mallocSizeOf) + - symbolicLinks.sizeOfExcludingThis(mallocSizeOf) + - SizeOfVectorExcludingThis(funcPtrTables, mallocSizeOf); - - for (const Uint32Vector& offsets : symbolicLinks) - size += offsets.sizeOfExcludingThis(mallocSizeOf); - - return size; + return internalLinks.sizeOfExcludingThis(mallocSizeOf) + + symbolicLinks.sizeOfExcludingThis(mallocSizeOf) + + SizeOfVectorExcludingThis(funcPtrTables, mallocSizeOf); } static size_t diff --git a/js/src/asmjs/WasmText.cpp b/js/src/asmjs/WasmText.cpp index 685b96604ab2..468a50c29d41 100644 --- a/js/src/asmjs/WasmText.cpp +++ b/js/src/asmjs/WasmText.cpp @@ -44,6 +44,7 @@ using mozilla::PositiveInfinity; using mozilla::SpecificNaN; static const unsigned AST_LIFO_DEFAULT_CHUNK_SIZE = 4096; +static const uint32_t WasmNoIndex = UINT32_MAX; /*****************************************************************************/ // wasm AST @@ -58,8 +59,72 @@ using WasmAstVector = mozilla::Vector>; template using WasmAstHashMap = HashMap>; +class WasmName +{ + const char16_t* begin_; + const char16_t* end_; + public: + WasmName(const char16_t* begin, size_t length) : begin_(begin), end_(begin + length) {} + WasmName() : begin_(nullptr), end_(nullptr) {} + const char16_t* begin() const { return begin_; } + const char16_t* end() const { return end_; } + size_t length() const { MOZ_ASSERT(begin_ != nullptr); return end_ - begin_; } + bool isEmpty() const { return begin_ == nullptr; } +}; + +class WasmRef +{ + WasmName name_; + uint32_t index_; + + public: + WasmRef() + : index_(WasmNoIndex) + { + MOZ_ASSERT(isInvalid()); + } + WasmRef(WasmName name, uint32_t index) + : name_(name), index_(index) + { + MOZ_ASSERT(name.isEmpty() ^ (index == WasmNoIndex)); + MOZ_ASSERT(!isInvalid()); + } + bool isInvalid() const { + return name_.isEmpty() && index_ == WasmNoIndex; + } + WasmName name() const { + return name_; + } + size_t index() const { + MOZ_ASSERT(index_ != WasmNoIndex); + return index_; + } + void setIndex(uint32_t index) { + MOZ_ASSERT(index_ == WasmNoIndex); + index_ = index; + } +}; + +struct WasmNameHasher +{ + typedef const WasmName Lookup; + static js::HashNumber hash(Lookup l) { + return mozilla::HashString(l.begin(), l.length()); + } + static bool match(const WasmName key, Lookup lookup) { + if (key.length() != lookup.length()) + return false; + if (key.begin() == lookup.begin()) + return true; + return EqualChars(key.begin(), lookup.begin(), key.length()); + } +}; + +using WasmNameMap = HashMap; + typedef WasmAstVector WasmAstValTypeVector; typedef WasmAstVector WasmAstExprVector; +typedef mozilla::Vector> WasmNameVector; struct WasmAstBase { @@ -70,6 +135,7 @@ struct WasmAstBase class WasmAstSig : public WasmAstBase { + WasmName name_; WasmAstValTypeVector args_; ExprType ret_; @@ -82,8 +148,9 @@ class WasmAstSig : public WasmAstBase : args_(Move(args)), ret_(ret) {} - WasmAstSig(WasmAstSig&& rhs) - : args_(Move(rhs.args_)), + WasmAstSig(WasmName name, WasmAstSig&& rhs) + : name_(name), + args_(Move(rhs.args_)), ret_(rhs.ret_) {} void operator=(WasmAstSig&& rhs) { @@ -96,6 +163,9 @@ class WasmAstSig : public WasmAstBase ExprType ret() const { return ret_; } + WasmName name() const { + return name_; + } bool operator==(const WasmAstSig& rhs) const { return ret() == rhs.ret() && EqualContainers(args(), rhs.args()); } @@ -171,33 +241,33 @@ class WasmAstConst : public WasmAstExpr class WasmAstGetLocal : public WasmAstExpr { - uint32_t localIndex_; + WasmRef local_; public: static const WasmAstExprKind Kind = WasmAstExprKind::GetLocal; - explicit WasmAstGetLocal(uint32_t localIndex) + explicit WasmAstGetLocal(WasmRef local) : WasmAstExpr(Kind), - localIndex_(localIndex) + local_(local) {} - uint32_t localIndex() const { - return localIndex_; + WasmRef& local() { + return local_; } }; class WasmAstSetLocal : public WasmAstExpr { - uint32_t localIndex_; + WasmRef local_; WasmAstExpr& value_; public: static const WasmAstExprKind Kind = WasmAstExprKind::SetLocal; - WasmAstSetLocal(uint32_t localIndex, WasmAstExpr& value) + WasmAstSetLocal(WasmRef local, WasmAstExpr& value) : WasmAstExpr(Kind), - localIndex_(localIndex), + local_(local), value_(value) {} - uint32_t localIndex() const { - return localIndex_; + WasmRef& local() { + return local_; } WasmAstExpr& value() const { return value_; @@ -221,33 +291,32 @@ class WasmAstBlock : public WasmAstExpr class WasmAstCall : public WasmAstExpr { Expr expr_; - uint32_t index_; + WasmRef func_; WasmAstExprVector args_; public: static const WasmAstExprKind Kind = WasmAstExprKind::Call; - WasmAstCall(Expr expr, uint32_t index, WasmAstExprVector&& args) - : WasmAstExpr(Kind), expr_(expr), index_(index), args_(Move(args)) + WasmAstCall(Expr expr, WasmRef func, WasmAstExprVector&& args) + : WasmAstExpr(Kind), expr_(expr), func_(func), args_(Move(args)) {} Expr expr() const { return expr_; } - uint32_t index() const { return index_; } + WasmRef& func() { return func_; } const WasmAstExprVector& args() const { return args_; } }; class WasmAstCallIndirect : public WasmAstExpr { - uint32_t sigIndex_; + WasmRef sig_; WasmAstExpr* index_; WasmAstExprVector args_; public: static const WasmAstExprKind Kind = WasmAstExprKind::CallIndirect; - WasmAstCallIndirect(uint32_t sigIndex, WasmAstExpr* index, WasmAstExprVector&& args) - : WasmAstExpr(Kind), sigIndex_(sigIndex), index_(index), args_(Move(args)) + WasmAstCallIndirect(WasmRef sig, WasmAstExpr* index, WasmAstExprVector&& args) + : WasmAstExpr(Kind), sig_(sig), index_(index), args_(Move(args)) {} - - uint32_t sigIndex() const { return sigIndex_; } + WasmRef& sig() { return sig_; } WasmAstExpr* index() const { return index_; } const WasmAstExprVector& args() const { return args_; } }; @@ -336,33 +405,42 @@ class WasmAstStore : public WasmAstExpr class WasmAstFunc : public WasmAstNode { - const uint32_t sigIndex_; + WasmName name_; + WasmRef sig_; WasmAstValTypeVector varTypes_; + WasmNameVector varNames_; WasmAstExprVector body_; public: - WasmAstFunc(uint32_t sigIndex, WasmAstValTypeVector&& varTypes, WasmAstExprVector&& body) - : sigIndex_(sigIndex), + WasmAstFunc(WasmName name, WasmRef sig, WasmAstValTypeVector&& varTypes, + WasmNameVector&& varNames, WasmAstExprVector&& body) + : name_(name), + sig_(sig), varTypes_(Move(varTypes)), + varNames_(Move(varNames)), body_(Move(body)) {} - uint32_t sigIndex() const { return sigIndex_; } + WasmRef& sig() { return sig_; } const WasmAstValTypeVector& varTypes() const { return varTypes_; } + const WasmNameVector& varNames() const { return varNames_; } const WasmAstExprVector& body() const { return body_; } + WasmName name() const { return name_; } }; class WasmAstImport : public WasmAstNode { - TwoByteChars module_; - TwoByteChars func_; + WasmName name_; + WasmName module_; + WasmName func_; uint32_t sigIndex_; public: - WasmAstImport(TwoByteChars module, TwoByteChars func, uint32_t sigIndex) - : module_(module), func_(func), sigIndex_(sigIndex) + WasmAstImport(WasmName name, WasmName module, WasmName func, uint32_t sigIndex) + : name_(name), module_(module), func_(func), sigIndex_(sigIndex) {} - TwoByteChars module() const { return module_; } - TwoByteChars func() const { return func_; } + WasmName name() const { return name_; } + WasmName module() const { return module_; } + WasmName func() const { return func_; } uint32_t sigIndex() const { return sigIndex_; } }; @@ -370,27 +448,23 @@ enum class WasmAstExportKind { Func, Memory }; class WasmAstExport : public WasmAstNode { - TwoByteChars name_; + WasmName name_; WasmAstExportKind kind_; - union { - uint32_t funcIndex_; - } u; + WasmRef func_; public: - WasmAstExport(TwoByteChars name, uint32_t funcIndex) - : name_(name), kind_(WasmAstExportKind::Func) - { - u.funcIndex_ = funcIndex; - } - explicit WasmAstExport(TwoByteChars name) + WasmAstExport(WasmName name, WasmRef func) + : name_(name), kind_(WasmAstExportKind::Func), func_(func) + {} + explicit WasmAstExport(WasmName name) : name_(name), kind_(WasmAstExportKind::Memory) {} - TwoByteChars name() const { return name_; } + WasmName name() const { return name_; } WasmAstExportKind kind() const { return kind_; } - size_t funcIndex() const { MOZ_ASSERT(kind_ == WasmAstExportKind::Func); return u.funcIndex_; } + WasmRef& func() { return func_; } }; -typedef WasmAstVector WasmAstTableElemVector; +typedef WasmAstVector WasmAstTableElemVector; class WasmAstTable : public WasmAstNode { @@ -398,20 +472,20 @@ class WasmAstTable : public WasmAstNode public: explicit WasmAstTable(WasmAstTableElemVector&& elems) : elems_(Move(elems)) {} - const WasmAstTableElemVector& elems() const { return elems_; } + WasmAstTableElemVector& elems() { return elems_; } }; class WasmAstSegment : public WasmAstNode { uint32_t offset_; - TwoByteChars text_; + WasmName text_; public: - WasmAstSegment(uint32_t offset, TwoByteChars text) + WasmAstSegment(uint32_t offset, WasmName text) : offset_(offset), text_(text) {} uint32_t offset() const { return offset_; } - TwoByteChars text() const { return text_; } + WasmName text() const { return text_; } }; typedef WasmAstVector WasmAstSegmentVector; @@ -477,7 +551,7 @@ class WasmAstModule : public WasmAstNode return true; } *sigIndex = sigs_.length(); - return sigs_.append(new (lifo_) WasmAstSig(Move(sig))) && + return sigs_.append(new (lifo_) WasmAstSig(WasmName(), Move(sig))) && sigMap_.add(p, sigs_.back(), *sigIndex); } bool append(WasmAstSig* sig) { @@ -514,7 +588,7 @@ class WasmAstModule : public WasmAstNode table_ = table; return true; } - const WasmAstTable* maybeTable() const { + WasmAstTable* maybeTable() const { return table_; } }; @@ -737,12 +811,15 @@ class WasmToken const char16_t* end() const { return end_; } - TwoByteChars text() const { + WasmName text() const { MOZ_ASSERT(kind_ == Text); MOZ_ASSERT(begin_[0] == '"'); MOZ_ASSERT(end_[-1] == '"'); MOZ_ASSERT(end_ - begin_ >= 2); - return TwoByteChars(begin_ + 1, end_ - begin_ - 2); + return WasmName(begin_ + 1, end_ - begin_ - 2); + } + WasmName name() const { + return WasmName(begin_, end_ - begin_); } uint32_t index() const { MOZ_ASSERT(kind_ == Index); @@ -985,7 +1062,6 @@ class WasmTokenStream unsigned column = token.begin() - lineStart_ + 1; error->reset(JS_smprintf("parsing wasm text at %u:%u", line_, column)); } - WasmToken peek() { if (!lookaheadDepth_) { lookahead_[lookaheadIndex_] = next(); @@ -1020,7 +1096,35 @@ class WasmTokenStream } bool getIf(WasmToken::Kind kind) { WasmToken token; - return getIf(kind, &token); + if (getIf(kind, &token)) + return true; + return false; + } + WasmName getIfName() { + WasmToken token; + if (getIf(WasmToken::Name, &token)) + return token.name(); + return WasmName(); + } + bool getRef(WasmRef* ref) { + WasmToken token = get(); + switch (token.kind()) { + case WasmToken::Name: + *ref = WasmRef(token.name(), WasmNoIndex); + break; + case WasmToken::Index: + *ref = WasmRef(WasmName(), token.index()); + break; + default: + return false; + } + return true; + } + bool getIfRef(WasmRef* ref) { + WasmToken token = peek(); + if (token.kind() == WasmToken::Name || token.kind() == WasmToken::Index) + return getRef(ref); + return false; } bool match(WasmToken::Kind expect, WasmToken* token, UniqueChars* error) { *token = get(); @@ -1719,6 +1823,10 @@ struct WasmParseContext dtoaState(NewDtoaState()) {} + bool fail(const char* message) { + error->reset(JS_smprintf(message)); + return false; + } ~WasmParseContext() { DestroyDtoaState(dtoaState); } @@ -1778,22 +1886,22 @@ ParseCall(WasmParseContext& c, Expr expr) { MOZ_ASSERT(expr == Expr::Call || expr == Expr::CallImport); - WasmToken index; - if (!c.ts.match(WasmToken::Index, &index, c.error)) + WasmRef func; + if (!c.ts.getRef(&func)) return nullptr; WasmAstExprVector args(c.lifo); if (!ParseArgs(c, &args)) return nullptr; - return new(c.lifo) WasmAstCall(expr, index.index(), Move(args)); + return new(c.lifo) WasmAstCall(expr, func, Move(args)); } static WasmAstCallIndirect* ParseCallIndirect(WasmParseContext& c) { - WasmToken sigIndex; - if (!c.ts.match(WasmToken::Index, &sigIndex, c.error)) + WasmRef sig; + if (!c.ts.getRef(&sig)) return nullptr; WasmAstExpr* index = ParseExpr(c); @@ -1804,7 +1912,7 @@ ParseCallIndirect(WasmParseContext& c) if (!ParseArgs(c, &args)) return nullptr; - return new(c.lifo) WasmAstCallIndirect(sigIndex.index(), index, Move(args)); + return new(c.lifo) WasmAstCallIndirect(sig, index, Move(args)); } static uint_fast8_t @@ -2074,7 +2182,7 @@ ParseConst(WasmParseContext& c, WasmToken constToken) case ValType::I64: { switch (val.kind()) { case WasmToken::Index: - return new(c.lifo) WasmAstConst(Val(val.index())); + return new(c.lifo) WasmAstConst(Val(uint64_t(val.index()))); case WasmToken::UnsignedInteger: return new(c.lifo) WasmAstConst(Val(val.uint())); case WasmToken::SignedInteger: @@ -2110,25 +2218,25 @@ ParseConst(WasmParseContext& c, WasmToken constToken) static WasmAstGetLocal* ParseGetLocal(WasmParseContext& c) { - WasmToken localIndex; - if (!c.ts.match(WasmToken::Index, &localIndex, c.error)) + WasmRef local; + if (!c.ts.getRef(&local)) return nullptr; - return new(c.lifo) WasmAstGetLocal(localIndex.index()); + return new(c.lifo) WasmAstGetLocal(local); } static WasmAstSetLocal* ParseSetLocal(WasmParseContext& c) { - WasmToken localIndex; - if (!c.ts.match(WasmToken::Index, &localIndex, c.error)) + WasmRef local; + if (!c.ts.getRef(&local)) return nullptr; WasmAstExpr* value = ParseExpr(c); if (!value) return nullptr; - return new(c.lifo) WasmAstSetLocal(localIndex.index(), *value); + return new(c.lifo) WasmAstSetLocal(local, *value); } static WasmAstUnaryOperator* @@ -2397,24 +2505,22 @@ ParseResult(WasmParseContext& c, ExprType* result) return true; } -static const uint32_t BadSigIndex = UINT32_MAX; - static WasmAstFunc* ParseFunc(WasmParseContext& c, WasmAstModule* module) { WasmAstValTypeVector vars(c.lifo); WasmAstValTypeVector args(c.lifo); - ExprType result = ExprType::Void; + WasmNameVector varNames(c.lifo); - uint32_t sigIndex = BadSigIndex; + WasmName funcName = c.ts.getIfName(); + + WasmRef sig; WasmToken openParen; if (c.ts.getIf(WasmToken::OpenParen, &openParen)) { if (c.ts.getIf(WasmToken::Type)) { - WasmToken sigToken; - if (!c.ts.match(WasmToken::Index, &sigToken, c.error)) + if (!c.ts.getRef(&sig)) return nullptr; - sigIndex = sigToken.index(); if (!c.ts.match(WasmToken::CloseParen, c.error)) return nullptr; } else { @@ -2423,18 +2529,20 @@ ParseFunc(WasmParseContext& c, WasmAstModule* module) } WasmAstExprVector body(c.lifo); + ExprType result = ExprType::Void; while (c.ts.getIf(WasmToken::OpenParen)) { WasmToken token = c.ts.get(); switch (token.kind()) { case WasmToken::Local: - if (!ParseValueType(c, &vars)) - return nullptr; - break; - case WasmToken::Param: - if (!ParseValueType(c, &args)) + case WasmToken::Param: { + WasmName name = c.ts.getIfName(); + if (!varNames.append(name)) + return nullptr; + if (!ParseValueType(c, token.kind() == WasmToken::Local ? &vars : &args)) return nullptr; break; + } case WasmToken::Result: if (!ParseResult(c, &result)) return nullptr; @@ -2450,12 +2558,14 @@ ParseFunc(WasmParseContext& c, WasmAstModule* module) return nullptr; } - if (sigIndex == BadSigIndex) { + if (sig.isInvalid()) { + uint32_t sigIndex; if (!module->declare(WasmAstSig(Move(args), result), &sigIndex)) return nullptr; + sig.setIndex(sigIndex); } - return new(c.lifo) WasmAstFunc(sigIndex, Move(vars), Move(body)); + return new(c.lifo) WasmAstFunc(funcName, sig, Move(vars), Move(varNames), Move(body)); } static bool @@ -2490,6 +2600,8 @@ ParseFuncType(WasmParseContext& c, WasmAstSig* sig) static WasmAstSig* ParseTypeDef(WasmParseContext& c) { + WasmName name = c.ts.getIfName(); + if (!c.ts.match(WasmToken::OpenParen, c.error)) return nullptr; if (!c.ts.match(WasmToken::Func, c.error)) @@ -2502,7 +2614,7 @@ ParseTypeDef(WasmParseContext& c) if (!c.ts.match(WasmToken::CloseParen, c.error)) return nullptr; - return new(c.lifo) WasmAstSig(Move(sig)); + return new(c.lifo) WasmAstSig(name, Move(sig)); } static WasmAstSegment* @@ -2544,6 +2656,8 @@ ParseMemory(WasmParseContext& c) static WasmAstImport* ParseImport(WasmParseContext& c, WasmAstModule* module) { + WasmName name = c.ts.getIfName(); + WasmToken moduleName; if (!c.ts.match(WasmToken::Text, &moduleName, c.error)) return nullptr; @@ -2560,7 +2674,7 @@ ParseImport(WasmParseContext& c, WasmAstModule* module) if (!module->declare(Move(sig), &sigIndex)) return nullptr; - return new(c.lifo) WasmAstImport(moduleName.text(), funcName.text(), sigIndex); + return new(c.lifo) WasmAstImport(name, moduleName.text(), funcName.text(), sigIndex); } static WasmAstExport* @@ -2573,7 +2687,9 @@ ParseExport(WasmParseContext& c) WasmToken exportee = c.ts.get(); switch (exportee.kind()) { case WasmToken::Index: - return new(c.lifo) WasmAstExport(name.text(), exportee.index()); + return new(c.lifo) WasmAstExport(name.text(), WasmRef(WasmName(), exportee.index())); + case WasmToken::Name: + return new(c.lifo) WasmAstExport(name.text(), WasmRef(exportee.name(), WasmNoIndex)); case WasmToken::Memory: return new(c.lifo) WasmAstExport(name.text()); default: @@ -2590,9 +2706,9 @@ ParseTable(WasmParseContext& c) { WasmAstTableElemVector elems(c.lifo); - WasmToken token; - while (c.ts.getIf(WasmToken::Index, &token)) { - if (!elems.append(token.index())) + WasmRef elem; + while (c.ts.getIfRef(&elem)) { + if (!elems.append(elem)) return nullptr; } @@ -2680,6 +2796,352 @@ ParseModule(const char16_t* text, LifoAlloc& lifo, UniqueChars* error) } // end anonymous namespace +/*****************************************************************************/ +// wasm name resolution + +namespace { + +class Resolver +{ + UniqueChars* error_; + WasmNameMap varMap_; + WasmNameMap sigMap_; + WasmNameMap funcMap_; + WasmNameMap importMap_; + + bool registerName(WasmNameMap& map, WasmName name, size_t index) { + WasmNameMap::AddPtr p = map.lookupForAdd(name); + if (!p) { + if (!map.add(p, name, index)) + return false; + } else { + return false; + } + return true; + } + bool resolveName(WasmNameMap& map, WasmName name, size_t* index) { + WasmNameMap::Ptr p = map.lookup(name); + if (p) { + *index = p->value(); + return true; + } + return false; + } + bool resolveRef(WasmNameMap& map, WasmRef& ref) { + WasmNameMap::Ptr p = map.lookup(ref.name()); + if (p) { + ref.setIndex(p->value()); + return true; + } + return false; + } + + public: + explicit Resolver(UniqueChars* error) + : error_(error) + {} + bool init() { + return sigMap_.init() && funcMap_.init() && importMap_.init() && varMap_.init(); + } + void beginFunc() { + varMap_.clear(); + } + bool registerSigName(WasmName name, size_t index) { + return registerName(sigMap_, name, index); + } + bool registerFuncName(WasmName name, size_t index) { + return registerName(funcMap_, name, index); + } + bool registerImportName(WasmName name, size_t index) { + return registerName(importMap_, name, index); + } + bool registerVarName(WasmName name, size_t index) { + return registerName(varMap_, name, index); + } + bool resolveSigRef(WasmRef& ref) { + return resolveRef(sigMap_, ref); + } + bool resolveFuncRef(WasmRef& ref) { + return resolveRef(funcMap_, ref); + } + bool resolveImportRef(WasmRef& ref) { + return resolveRef(importMap_, ref); + } + bool resolveVarRef(WasmRef& ref) { + return resolveRef(varMap_, ref); + } + bool fail(const char*message) { + error_->reset(JS_smprintf("%s", message)); + return false; + } +}; + +} // end anonymous namespace + +static bool +ResolveExpr(Resolver& r, WasmAstExpr& expr); + +static bool +ResolveBlock(Resolver& r, WasmAstBlock& b) +{ + size_t numExprs = b.exprs().length(); + for (size_t i = 0; i < numExprs; i++) { + if (!ResolveExpr(r, *b.exprs()[i])) + return false; + } + + return true; +} + +static bool +ResolveArgs(Resolver& r, const WasmAstExprVector& args) +{ + for (WasmAstExpr* arg : args) { + if (!ResolveExpr(r, *arg)) + return false; + } + + return true; +} + +static bool +ResolveCall(Resolver& r, WasmAstCall& c) +{ + if (!ResolveArgs(r, c.args())) + return false; + + if (c.func().name().isEmpty()) + return true; + + if (c.expr() == Expr::Call ? !r.resolveFuncRef(c.func()) + : !r.resolveImportRef(c.func())) { + return r.fail("function not found"); + } + + return true; +} + +static bool +ResolveCallIndirect(Resolver& r, WasmAstCallIndirect& c) +{ + if (!ResolveExpr(r, *c.index())) + return false; + + if (!ResolveArgs(r, c.args())) + return false; + + if (c.sig().name().isEmpty()) + return true; + + if (!r.resolveSigRef(c.sig())) + return r.fail("signature not found"); + + return true; +} + +static bool +ResolveGetLocal(Resolver& r, WasmAstGetLocal& gl) +{ + if (gl.local().name().isEmpty()) + return true; + + if (!r.resolveVarRef(gl.local())) + return r.fail("local not found"); + + return true; +} + +static bool +ResolveSetLocal(Resolver& r, WasmAstSetLocal& sl) +{ + if (!ResolveExpr(r, sl.value())) + return false; + + if (sl.local().name().isEmpty()) + return true; + + if (!r.resolveVarRef(sl.local())) + return r.fail("local not found"); + + return true; +} + +static bool +ResolveUnaryOperator(Resolver& r, WasmAstUnaryOperator& b) +{ + return ResolveExpr(r, *b.op()); +} + +static bool +ResolveBinaryOperator(Resolver& r, WasmAstBinaryOperator& b) +{ + return ResolveExpr(r, *b.lhs()) && + ResolveExpr(r, *b.rhs()); +} + +static bool +ResolveComparisonOperator(Resolver& r, WasmAstComparisonOperator& b) +{ + return ResolveExpr(r, *b.lhs()) && + ResolveExpr(r, *b.rhs()); +} + +static bool +ResolveConversionOperator(Resolver& r, WasmAstConversionOperator& b) +{ + return ResolveExpr(r, *b.op()); +} + +static bool +ResolveIfElse(Resolver& r, WasmAstIfElse& ie) +{ + return ResolveExpr(r, ie.cond()) && + ResolveExpr(r, ie.ifBody()) && + (!ie.hasElse() || ResolveExpr(r, ie.elseBody())); +} + +static bool +ResolveLoadStoreAddress(Resolver& r, const WasmAstLoadStoreAddress &address) +{ + return ResolveExpr(r, address.base()); +} + +static bool +ResolveLoad(Resolver& r, WasmAstLoad& l) +{ + return ResolveLoadStoreAddress(r, l.address()); +} + +static bool +ResolveStore(Resolver& r, WasmAstStore& s) +{ + return ResolveLoadStoreAddress(r, s.address()) && + ResolveExpr(r, s.value()); +} + +static bool +ResolveExpr(Resolver& r, WasmAstExpr& expr) +{ + switch (expr.kind()) { + case WasmAstExprKind::Nop: + return true; + case WasmAstExprKind::BinaryOperator: + return ResolveBinaryOperator(r, expr.as()); + case WasmAstExprKind::Block: + return ResolveBlock(r, expr.as()); + case WasmAstExprKind::Call: + return ResolveCall(r, expr.as()); + case WasmAstExprKind::CallIndirect: + return ResolveCallIndirect(r, expr.as()); + case WasmAstExprKind::ComparisonOperator: + return ResolveComparisonOperator(r, expr.as()); + case WasmAstExprKind::Const: + return true; + case WasmAstExprKind::ConversionOperator: + return ResolveConversionOperator(r, expr.as()); + case WasmAstExprKind::GetLocal: + return ResolveGetLocal(r, expr.as()); + case WasmAstExprKind::IfElse: + return ResolveIfElse(r, expr.as()); + case WasmAstExprKind::Load: + return ResolveLoad(r, expr.as()); + case WasmAstExprKind::SetLocal: + return ResolveSetLocal(r, expr.as()); + case WasmAstExprKind::Store: + return ResolveStore(r, expr.as()); + case WasmAstExprKind::UnaryOperator: + return ResolveUnaryOperator(r, expr.as()); + default:; + } + MOZ_CRASH("Bad expr kind"); +} + +static bool +ResolveFunc(Resolver& r, WasmAstFunc& func) +{ + r.beginFunc(); + + size_t numVars = func.varNames().length(); + for (size_t i = 0; i < numVars; i++) { + WasmName name = func.varNames()[i]; + if (name.isEmpty()) + continue; + if (!r.registerVarName(name, i)) + return r.fail("duplicate var"); + } + + for (WasmAstExpr* expr : func.body()) { + if (!ResolveExpr(r, *expr)) + return false; + } + return true; +} + +static bool +ResolveModule(LifoAlloc& lifo, WasmAstModule* module, UniqueChars* error) +{ + Resolver r(error); + + if (!r.init()) + return false; + + size_t numSigs = module->sigs().length(); + for (size_t i = 0; i < numSigs; i++) { + WasmAstSig* sig = module->sigs()[i]; + if (sig->name().isEmpty()) + continue; + if (!r.registerSigName(sig->name(), i)) + return r.fail("duplicate signature"); + } + + size_t numFuncs = module->funcs().length(); + for (size_t i = 0; i < numFuncs; i++) { + WasmAstFunc* func = module->funcs()[i]; + if (!func->sig().name().isEmpty()) { + if (!r.resolveSigRef(func->sig())) + return r.fail("signature not found"); + } + if (func->name().isEmpty()) + continue; + if (!r.registerFuncName(func->name(), i)) + return r.fail("duplicate function"); + } + + if (module->maybeTable()) { + for (WasmRef& ref : module->maybeTable()->elems()) { + if (ref.name().isEmpty()) + continue; + if (!r.resolveFuncRef(ref)) + return r.fail("function not found"); + } + } + + size_t numImports = module->imports().length(); + for (size_t i = 0; i < numImports; i++) { + WasmAstImport* imp = module->imports()[i]; + if (imp->name().isEmpty()) + continue; + if (!r.registerImportName(imp->name(), i)) + return r.fail("duplicate import"); + } + + for (WasmAstExport* export_ : module->exports()) { + if (export_->kind() != WasmAstExportKind::Func) + continue; + if (export_->func().name().isEmpty()) + continue; + if (!r.resolveFuncRef(export_->func())) + return r.fail("function not found"); + } + + for (WasmAstFunc* func : module->funcs()) { + if (!ResolveFunc(r, *func)) + return false; + } + + return true; +} + /*****************************************************************************/ // wasm function body serialization @@ -2721,7 +3183,7 @@ EncodeCall(Encoder& e, WasmAstCall& c) if (!e.writeExpr(c.expr())) return false; - if (!e.writeVarU32(c.index())) + if (!e.writeVarU32(c.func().index())) return false; if (!EncodeArgs(e, c.args())) @@ -2736,7 +3198,7 @@ EncodeCallIndirect(Encoder& e, WasmAstCallIndirect& c) if (!e.writeExpr(Expr::CallIndirect)) return false; - if (!e.writeVarU32(c.sigIndex())) + if (!e.writeVarU32(c.sig().index())) return false; if (!EncodeExpr(e, *c.index())) @@ -2774,14 +3236,14 @@ static bool EncodeGetLocal(Encoder& e, WasmAstGetLocal& gl) { return e.writeExpr(Expr::GetLocal) && - e.writeVarU32(gl.localIndex()); + e.writeVarU32(gl.local().index()); } static bool EncodeSetLocal(Encoder& e, WasmAstSetLocal& sl) { return e.writeExpr(Expr::SetLocal) && - e.writeVarU32(sl.localIndex()) && + e.writeVarU32(sl.local().index()) && EncodeExpr(e, sl.value()); } @@ -2937,7 +3399,7 @@ EncodeDeclarationSection(Encoder& e, WasmAstModule& module) return false; for (WasmAstFunc* func : module.funcs()) { - if (!e.writeVarU32(func->sigIndex())) + if (!e.writeVarU32(func->sig().index())) return false; } @@ -2946,9 +3408,10 @@ EncodeDeclarationSection(Encoder& e, WasmAstModule& module) } static bool -EncodeCString(Encoder& e, TwoByteChars twoByteChars) +EncodeCString(Encoder& e, WasmName wasmName) { - UniqueChars utf8(JS::CharsToNewUTF8CharsZ(nullptr, twoByteChars).c_str()); + TwoByteChars range(wasmName.begin(), wasmName.length()); + UniqueChars utf8(JS::CharsToNewUTF8CharsZ(nullptr, range).c_str()); return utf8 && e.writeCString(utf8.get()); } @@ -3025,7 +3488,7 @@ EncodeMemorySection(Encoder& e, WasmAstModule& module) static bool EncodeFunctionExport(Encoder& e, WasmAstExport& exp) { - if (!e.writeVarU32(exp.funcIndex())) + if (!e.writeVarU32(exp.func().index())) return false; if (!EncodeCString(e, exp.name())) @@ -3096,8 +3559,8 @@ EncodeTableSection(Encoder& e, WasmAstModule& module) if (!e.writeVarU32(module.maybeTable()->elems().length())) return false; - for (uint32_t index : module.maybeTable()->elems()) { - if (!e.writeVarU32(index)) + for (WasmRef& ref : module.maybeTable()->elems()) { + if (!e.writeVarU32(ref.index())) return false; } @@ -3142,14 +3605,14 @@ EncodeDataSegment(Encoder& e, WasmAstSegment& segment) if (!e.writeVarU32(segment.offset())) return false; - TwoByteChars text = segment.text(); + WasmName text = segment.text(); Vector bytes; if (!bytes.reserve(text.length())) return false; - const char16_t* cur = text.start().get(); - const char16_t* end = text.end().get(); + const char16_t* cur = text.begin(); + const char16_t* end = text.end(); while (cur != end) { uint8_t byte; MOZ_ALWAYS_TRUE(ConsumeTextByte(&cur, end, &byte)); @@ -3251,5 +3714,8 @@ wasm::TextToBinary(const char16_t* text, UniqueChars* error) if (!module) return nullptr; + if (!ResolveModule(lifo, module, error)) + return nullptr; + return EncodeModule(*module); } diff --git a/js/src/asmjs/WasmTypes.h b/js/src/asmjs/WasmTypes.h index 51b641f3c666..db471e491edf 100644 --- a/js/src/asmjs/WasmTypes.h +++ b/js/src/asmjs/WasmTypes.h @@ -196,6 +196,29 @@ ToMIRType(ExprType et) return IsVoid(et) ? jit::MIRType_None : ToMIRType(ValType(et)); } +static inline const char* +ToCString(ExprType type) +{ + switch (type) { + case ExprType::Void: return "void"; + case ExprType::I32: return "i32"; + case ExprType::I64: return "i64"; + case ExprType::F32: return "f32"; + case ExprType::F64: return "f64"; + case ExprType::I32x4: return "i32x4"; + case ExprType::F32x4: return "f32x4"; + case ExprType::B32x4: return "b32x4"; + case ExprType::Limit:; + } + MOZ_CRASH("bad expression type"); +} + +static inline const char* +ToCString(ValType type) +{ + return ToCString(ToExprType(type)); +} + // The Sig class represents a WebAssembly function signature which takes a list // of value types and returns an expression type. The engine uses two in-memory // representations of the argument Vector's memory (when elements do not fit diff --git a/js/src/builtin/SIMD.cpp b/js/src/builtin/SIMD.cpp index dc33047a1ee3..8e3ff21d3f2a 100644 --- a/js/src/builtin/SIMD.cpp +++ b/js/src/builtin/SIMD.cpp @@ -39,19 +39,6 @@ using mozilla::NumberIsInt32; static_assert(unsigned(SimdType::Count) == 12, "sync with TypedObjectConstants.h"); -PropertyName* -js::SimdTypeToName(JSContext* cx, SimdType type) -{ - switch (type) { - case SimdType::Int32x4: return cx->names().Int32x4; - case SimdType::Float32x4: return cx->names().Float32x4; - case SimdType::Bool32x4: return cx->names().Bool32x4; - default: break; - } - MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected SIMD type"); -} - - static bool CheckVectorObject(HandleValue v, SimdType expectedType) { @@ -107,6 +94,30 @@ js::SimdTypeToString(SimdType type) return ""; } +PropertyName* +js::SimdTypeToName(const JSAtomState& atoms, SimdType type) +{ + switch (type) { +#define CASE_(TypeName) case SimdType::TypeName: return atoms.TypeName; + FOR_EACH_SIMD(CASE_) +#undef CASE_ + case SimdType::Count: break; + } + MOZ_CRASH("bad SIMD type"); +} + +bool +js::IsSimdTypeName(const JSAtomState& atoms, const PropertyName* name, SimdType* type) +{ +#define CHECK_(TypeName) if (name == atoms.TypeName) { \ + *type = SimdType::TypeName; \ + return true; \ + } + FOR_EACH_SIMD(CHECK_) +#undef CHECK_ + return false; +} + static inline bool ErrorBadArgs(JSContext* cx) { diff --git a/js/src/builtin/SIMD.h b/js/src/builtin/SIMD.h index 7a7e09412514..eab6c6e8f780 100644 --- a/js/src/builtin/SIMD.h +++ b/js/src/builtin/SIMD.h @@ -250,8 +250,6 @@ V(subSaturate, (BinaryFunc), 2) \ V(shiftLeftByScalar, (BinaryScalar), 2) \ V(shiftRightByScalar, (BinaryScalar), 2) \ - V(shiftRightArithmeticByScalar, (BinaryScalar), 2) \ - V(shiftRightLogicalByScalar, (BinaryScalar), 2) \ V(xor, (BinaryFunc), 2) #define INT8X16_TERNARY_FUNCTION_LIST(V) \ @@ -301,8 +299,6 @@ V(subSaturate, (BinaryFunc), 2) \ V(shiftLeftByScalar, (BinaryScalar), 2) \ V(shiftRightByScalar, (BinaryScalar), 2) \ - V(shiftRightArithmeticByScalar, (BinaryScalar), 2) \ - V(shiftRightLogicalByScalar, (BinaryScalar), 2) \ V(xor, (BinaryFunc), 2) #define UINT8X16_TERNARY_FUNCTION_LIST(V) \ @@ -352,8 +348,6 @@ V(subSaturate, (BinaryFunc), 2) \ V(shiftLeftByScalar, (BinaryScalar), 2) \ V(shiftRightByScalar, (BinaryScalar), 2) \ - V(shiftRightArithmeticByScalar, (BinaryScalar), 2) \ - V(shiftRightLogicalByScalar, (BinaryScalar), 2) \ V(xor, (BinaryFunc), 2) #define INT16X8_TERNARY_FUNCTION_LIST(V) \ @@ -403,8 +397,6 @@ V(subSaturate, (BinaryFunc), 2) \ V(shiftLeftByScalar, (BinaryScalar), 2) \ V(shiftRightByScalar, (BinaryScalar), 2) \ - V(shiftRightArithmeticByScalar, (BinaryScalar), 2) \ - V(shiftRightLogicalByScalar, (BinaryScalar), 2) \ V(xor, (BinaryFunc), 2) #define UINT16X8_TERNARY_FUNCTION_LIST(V) \ @@ -456,8 +448,6 @@ V(sub, (BinaryFunc), 2) \ V(shiftLeftByScalar, (BinaryScalar), 2) \ V(shiftRightByScalar, (BinaryScalar), 2) \ - V(shiftRightArithmeticByScalar, (BinaryScalar), 2) \ - V(shiftRightLogicalByScalar, (BinaryScalar), 2) \ V(xor, (BinaryFunc), 2) #define INT32X4_TERNARY_FUNCTION_LIST(V) \ @@ -512,8 +502,6 @@ V(sub, (BinaryFunc), 2) \ V(shiftLeftByScalar, (BinaryScalar), 2) \ V(shiftRightByScalar, (BinaryScalar), 2) \ - V(shiftRightArithmeticByScalar, (BinaryScalar), 2) \ - V(shiftRightLogicalByScalar, (BinaryScalar), 2) \ V(xor, (BinaryFunc), 2) #define UINT32X4_TERNARY_FUNCTION_LIST(V) \ @@ -586,9 +574,7 @@ // Bitwise shifts defined on integer SIMD types. #define FOREACH_SHIFT_SIMD_OP(_) \ _(shiftLeftByScalar) \ - _(shiftRightByScalar) \ - _(shiftRightArithmeticByScalar) \ - _(shiftRightLogicalByScalar) + _(shiftRightByScalar) // Unary arithmetic operators defined on numeric SIMD types. #define FOREACH_NUMERIC_SIMD_UNOP(_) \ @@ -741,9 +727,13 @@ _(fromFloat32x4) \ _(fromFloat32x4Bits) \ _(fromInt32x4) \ - _(fromInt32x4Bits) + _(fromInt32x4Bits) \ + _(fromUint32x4) \ + _(fromUint32x4Bits) -// All operations on Int32x4 in the asm.js world +// All operations on Int32x4 or Uint32x4 in the asm.js world. +// Note: this does not include conversions and casts to/from Uint32x4 because +// this list is shared between Int32x4 and Uint32x4. #define FORALL_INT32X4_ASMJS_OP(_) \ FORALL_INT_SIMD_OP(_) \ FOREACH_MEMORY_X4_SIMD_OP(_) \ @@ -755,27 +745,9 @@ FORALL_FLOAT_SIMD_OP(_) \ FOREACH_MEMORY_X4_SIMD_OP(_) \ _(fromInt32x4) \ - _(fromInt32x4Bits) - -// TODO: remove when all SIMD calls are inlined (bug 1112155) -#define ION_COMMONX4_SIMD_OP(_) \ - FOREACH_NUMERIC_SIMD_BINOP(_) \ - _(extractLane) \ - _(replaceLane) \ - _(select) \ - _(splat) \ - _(neg) \ - _(swizzle) \ - _(shuffle) \ - _(load) \ - _(load1) \ - _(load2) \ - _(load3) \ - _(store) \ - _(store1) \ - _(store2) \ - _(store3) \ - _(check) + _(fromInt32x4Bits) \ + _(fromUint32x4) \ + _(fromUint32x4Bits) namespace js { @@ -1117,7 +1089,12 @@ struct Bool64x2 { } }; -PropertyName* SimdTypeToName(JSContext* cx, SimdType type); +// Get the well known name of the SIMD.* object corresponding to type. +PropertyName* SimdTypeToName(const JSAtomState& atoms, SimdType type); + +// Check if name is the well known name of a SIMD type. +// Returns true and sets *type iff name is known. +bool IsSimdTypeName(const JSAtomState& atoms, const PropertyName* name, SimdType* type); const char* SimdTypeToString(SimdType type); diff --git a/js/src/configure.in b/js/src/configure.in index d6a80a99a727..fa85cf44588a 100644 --- a/js/src/configure.in +++ b/js/src/configure.in @@ -3467,7 +3467,6 @@ AC_SUBST(USE_DEPENDENT_LIBS) AC_SUBST(MOZ_BUILD_ROOT) -AC_SUBST(MOZ_POST_DSO_LIB_COMMAND) AC_SUBST(MOZ_POST_PROGRAM_COMMAND) AC_SUBST(MOZ_APP_NAME) diff --git a/js/src/gc/Heap.h b/js/src/gc/Heap.h index 5f8a2353528d..30a8f646cd13 100644 --- a/js/src/gc/Heap.h +++ b/js/src/gc/Heap.h @@ -744,6 +744,7 @@ struct Arena private: static JS_FRIEND_DATA(const uint32_t) ThingSizes[]; static JS_FRIEND_DATA(const uint32_t) FirstThingOffsets[]; + static const uint32_t ThingsPerArena[]; public: static void staticAsserts(); @@ -756,17 +757,12 @@ struct Arena return FirstThingOffsets[size_t(kind)]; } - static size_t thingsPerArena(size_t thingSize) { - MOZ_ASSERT(thingSize % CellSize == 0); - - /* We should be able to fit FreeSpan in any GC thing. */ - MOZ_ASSERT(thingSize >= sizeof(FreeSpan)); - - return (ArenaSize - sizeof(ArenaHeader)) / thingSize; + static size_t thingsPerArena(AllocKind kind) { + return ThingsPerArena[size_t(kind)]; } - static size_t thingsSpan(size_t thingSize) { - return thingsPerArena(thingSize) * thingSize; + static size_t thingsSpan(AllocKind kind) { + return thingsPerArena(kind) * thingSize(kind); } static bool isAligned(uintptr_t thing, size_t thingSize) { diff --git a/js/src/jit-test/tests/SIMD/bug1248503.js b/js/src/jit-test/tests/SIMD/bug1248503.js index 36913faba94a..e121cea1d1d3 100644 --- a/js/src/jit-test/tests/SIMD/bug1248503.js +++ b/js/src/jit-test/tests/SIMD/bug1248503.js @@ -1,3 +1,6 @@ +if (typeof SIMD !== 'object') + quit(0); + function assertEqVec(v, w) { [0].forEach(i => v, w); function assertEqX4(...opts) {} diff --git a/js/src/jit-test/tests/SIMD/shift.js b/js/src/jit-test/tests/SIMD/shift.js index 14fddedea2d8..9975d0f871b3 100644 --- a/js/src/jit-test/tests/SIMD/shift.js +++ b/js/src/jit-test/tests/SIMD/shift.js @@ -10,12 +10,17 @@ function lsh(count) { return curry(binaryLsh, count); } function binaryRsh(count, v) { if (count>>>0 >= 32) count = 31; return (v >> count) | 0; } function rsh(count) { return curry(binaryRsh, count); } -function binaryUrsh(count, v) { if (count>>>0 >= 32) return 0; return (v >>> count) | 0; } +function binaryUlsh(count, v) { if (count>>>0 >= 32) return 0; return (v << count) >>> 0; } +function ulsh(count) { return curry(binaryUlsh, count); } + +function binaryUrsh(count, v) { if (count>>>0 >= 32) return 0; return v >>> count; } function ursh(count) { return curry(binaryUrsh, count); } function f() { var v = SIMD.Int32x4(1, 2, -3, 4); + var u = SIMD.Uint32x4(1, 0x55005500, -3, 0xaa00aa00); var a = [1, 2, -3, 4]; + var b = [1, 0x55005500, -3, 0xaa00aa00]; var zeros = [0,0,0,0]; var shifts = [-1, 0, 1, 31, 32]; @@ -30,20 +35,6 @@ function f() { assertEqX4(SIMD.Int32x4.shiftLeftByScalar(v, 31), a.map(lsh(31))); assertEqX4(SIMD.Int32x4.shiftLeftByScalar(v, 32), a.map(lsh(32))); - assertEqX4(SIMD.Int32x4.shiftRightArithmeticByScalar(v, -1), a.map(rsh(31))); - assertEqX4(SIMD.Int32x4.shiftRightArithmeticByScalar(v, 0), a.map(rsh(0))); - assertEqX4(SIMD.Int32x4.shiftRightArithmeticByScalar(v, 1), a.map(rsh(1))); - assertEqX4(SIMD.Int32x4.shiftRightArithmeticByScalar(v, 2), a.map(rsh(2))); - assertEqX4(SIMD.Int32x4.shiftRightArithmeticByScalar(v, 31), a.map(rsh(31))); - assertEqX4(SIMD.Int32x4.shiftRightArithmeticByScalar(v, 32), a.map(rsh(31))); - - assertEqX4(SIMD.Int32x4.shiftRightLogicalByScalar(v, -1), a.map(ursh(-1))); - assertEqX4(SIMD.Int32x4.shiftRightLogicalByScalar(v, 0), a.map(ursh(0))); - assertEqX4(SIMD.Int32x4.shiftRightLogicalByScalar(v, 1), a.map(ursh(1))); - assertEqX4(SIMD.Int32x4.shiftRightLogicalByScalar(v, 2), a.map(ursh(2))); - assertEqX4(SIMD.Int32x4.shiftRightLogicalByScalar(v, 31), a.map(ursh(31))); - assertEqX4(SIMD.Int32x4.shiftRightLogicalByScalar(v, 32), a.map(ursh(32))); - assertEqX4(SIMD.Int32x4.shiftRightByScalar(v, -1), a.map(rsh(31))); assertEqX4(SIMD.Int32x4.shiftRightByScalar(v, 0), a.map(rsh(0))); assertEqX4(SIMD.Int32x4.shiftRightByScalar(v, 1), a.map(rsh(1))); @@ -51,11 +42,28 @@ function f() { assertEqX4(SIMD.Int32x4.shiftRightByScalar(v, 31), a.map(rsh(31))); assertEqX4(SIMD.Int32x4.shiftRightByScalar(v, 32), a.map(rsh(31))); + assertEqX4(SIMD.Uint32x4.shiftLeftByScalar(u, -1), b.map(ulsh(-1))); + assertEqX4(SIMD.Uint32x4.shiftLeftByScalar(u, 0), b.map(ulsh(0))); + assertEqX4(SIMD.Uint32x4.shiftLeftByScalar(u, 1), b.map(ulsh(1))); + assertEqX4(SIMD.Uint32x4.shiftLeftByScalar(u, 2), b.map(ulsh(2))); + assertEqX4(SIMD.Uint32x4.shiftLeftByScalar(u, 31), b.map(ulsh(31))); + assertEqX4(SIMD.Uint32x4.shiftLeftByScalar(u, 32), b.map(ulsh(32))); + + assertEqX4(SIMD.Uint32x4.shiftRightByScalar(u, -1), b.map(ursh(-1))); + assertEqX4(SIMD.Uint32x4.shiftRightByScalar(u, 0), b.map(ursh(0))); + assertEqX4(SIMD.Uint32x4.shiftRightByScalar(u, 1), b.map(ursh(1))); + assertEqX4(SIMD.Uint32x4.shiftRightByScalar(u, 2), b.map(ursh(2))); + assertEqX4(SIMD.Uint32x4.shiftRightByScalar(u, 31), b.map(ursh(31))); + assertEqX4(SIMD.Uint32x4.shiftRightByScalar(u, 32), b.map(ursh(32))); + // Non constant shift counts var c = shifts[i % shifts.length]; + assertEqX4(SIMD.Int32x4.shiftLeftByScalar(v, c), a.map(lsh(c))); - assertEqX4(SIMD.Int32x4.shiftRightArithmeticByScalar(v, c), a.map(rsh(c))); - assertEqX4(SIMD.Int32x4.shiftRightLogicalByScalar(v, c), a.map(ursh(c))); + assertEqX4(SIMD.Int32x4.shiftRightByScalar(v, c), a.map(rsh(c))); + + assertEqX4(SIMD.Uint32x4.shiftLeftByScalar(u, c), b.map(ulsh(c))); + assertEqX4(SIMD.Uint32x4.shiftRightByScalar(u, c), b.map(ursh(c))); } return r; } diff --git a/js/src/jit-test/tests/asm.js/testSIMD.js b/js/src/jit-test/tests/asm.js/testSIMD.js index 2982f5591bef..6eefcacc99e1 100644 --- a/js/src/jit-test/tests/asm.js/testSIMD.js +++ b/js/src/jit-test/tests/asm.js/testSIMD.js @@ -16,6 +16,15 @@ const CI32 = 'var ci4 = i4.check;' const I32A = 'var i4a = i4.add;' const I32S = 'var i4s = i4.sub;' const I32M = 'var i4m = i4.mul;' +const I32U32 = 'var i4u4 = i4.fromUint32x4Bits;' + +const U32 = 'var u4 = glob.SIMD.Uint32x4;' +const CU32 = 'var cu4 = u4.check;' +const U32A = 'var u4a = u4.add;' +const U32S = 'var u4s = u4.sub;' +const U32M = 'var u4m = u4.mul;' +const U32I32 = 'var u4i4 = u4.fromInt32x4Bits;' + const F32 = 'var f4 = glob.SIMD.Float32x4;' const CF32 = 'var cf4 = f4.check;' const F32A = 'var f4a = f4.add;' @@ -27,6 +36,7 @@ const B32 = 'var b4 = glob.SIMD.Bool32x4;' const CB32 = 'var cb4 = b4.check;' const EXTI4 = 'var e = i4.extractLane;' +const EXTU4 = 'var e = u4.extractLane;' const EXTF4 = 'var e = f4.extractLane;' const EXTB4 = 'var e = b4.extractLane;' @@ -36,6 +46,7 @@ const ALLB4 = 'var allt=b4.allTrue;' const INT32_MAX = Math.pow(2, 31) - 1; const INT32_MIN = INT32_MAX + 1 | 0; +const UINT32_MAX = Math.pow(2, 32) - 1; const assertEqFFI = {assertEq:assertEq}; @@ -46,6 +57,15 @@ function CheckI4(header, code, expected) { assertEqX4(observed, expected); } +function CheckU4(header, code, expected) { + // code needs to contain a local called x. + header = USE_ASM + U32 + CU32 + EXTU4 + I32 + CI32 + I32U32 + header; + var observed = asmLink(asmCompile('glob', header + ';function f() {' + code + ';return ci4(i4u4(x))} return f'), this)(); + // We can't return an unsigned SIMD type. Return Int32x4, convert to unsigned here. + observed = SIMD.Uint32x4.fromInt32x4Bits(observed) + assertEqX4(observed, expected); +} + function CheckF4(header, code, expected) { // code needs to contain a local called x header = USE_ASM + F32 + CF32 + EXTF4 + header; @@ -176,6 +196,7 @@ assertAsmTypeFail('glob', USE_ASM + "function f() {var x=42; return x.signMask;} assertAsmTypeFail('glob', USE_ASM + "function f() {var x=42.; return x.signMask;} return f"); assertAsmTypeFail('glob', USE_ASM + FROUND + "function f() {var x=f32(42.); return x.signMask;} return f"); assertAsmTypeFail('glob', USE_ASM + I32 + 'function f() { var x=i4(1,2,3,4); return x.signMask | 0 } return f'); +assertAsmTypeFail('glob', USE_ASM + U32 + 'function f() { var x=u4(1,2,3,4); return x.signMask | 0 } return f'); assertAsmTypeFail('glob', USE_ASM + F32 + FROUND + 'var Infinity = glob.Infinity; function f() { var x=f4(0,0,0,0); x=f4(f32(1), f32(-13.37), f32(42), f32(-Infinity)); return x.signMask | 0 } return f'); // Check lane extraction. @@ -186,6 +207,11 @@ function CheckLanes(innerBody, type, expected) { coerceBefore = ''; coerceAfter = '|0'; extractLane = 'ei'; + } else if (type === SIMD.Uint32x4) { + // Coerce Uint32 lanes to double so they can be legally returned. + coerceBefore = '+'; + coerceAfter = ''; + extractLane = 'eu'; } else if (type === SIMD.Float32x4) { coerceBefore = '+'; coerceAfter = ''; @@ -201,9 +227,11 @@ function CheckLanes(innerBody, type, expected) { var lane = i; var laneCheckCode = `"use asm"; var i4=glob.SIMD.Int32x4; + var u4=glob.SIMD.Uint32x4; var f4=glob.SIMD.Float32x4; var b4=glob.SIMD.Bool32x4; var ei=i4.extractLane; + var eu=u4.extractLane; var ef=f4.extractLane; var eb=b4.extractLane; function f() {${innerBody}; return ${coerceBefore}${extractLane}(x, ${lane})${coerceAfter} } @@ -212,6 +240,7 @@ function CheckLanes(innerBody, type, expected) { } } function CheckLanesI4(innerBody, expected) { return CheckLanes(innerBody, SIMD.Int32x4, expected); } +function CheckLanesU4(innerBody, expected) { return CheckLanes(innerBody, SIMD.Uint32x4, expected); } function CheckLanesF4(innerBody, expected) { return CheckLanes(innerBody, SIMD.Float32x4, expected); } function CheckLanesB4(innerBody, expected) { return CheckLanes(innerBody, SIMD.Bool32x4, expected); } @@ -222,6 +251,13 @@ CheckLanesI4('var x=i4(1,2,3,4); var y=i4(5,6,7,8)', [1,2,3,4]); CheckLanesI4('var a=1; var b=i4(9,8,7,6); var c=13.37; var x=i4(1,2,3,4); var y=i4(5,6,7,8)', [1,2,3,4]); CheckLanesI4('var y=i4(5,6,7,8); var x=i4(1,2,3,4)', [1,2,3,4]); +CheckLanesU4('var x=u4(0,0,0,0);', [0,0,0,0]); +CheckLanesU4('var x=u4(1,2,3,4000000000);', [1,2,3,4000000000]); +CheckLanesU4('var x=u4(' + INT32_MIN + ',2,3,' + UINT32_MAX + ')', [INT32_MIN>>>0,2,3,UINT32_MAX]); +CheckLanesU4('var x=u4(1,2,3,4); var y=u4(5,6,7,8)', [1,2,3,4]); +CheckLanesU4('var a=1; var b=u4(9,8,7,6); var c=13.37; var x=u4(1,2,3,4); var y=u4(5,6,7,8)', [1,2,3,4]); +CheckLanesU4('var y=u4(5,6,7,8); var x=u4(1,2,3,4)', [1,2,3,4]); + CheckLanesF4('var x=f4(' + INT32_MAX + ', 2, 3, ' + INT32_MIN + ')', [INT32_MAX, 2, 3, INT32_MIN]); CheckLanesF4('var x=f4(' + (INT32_MAX + 1) + ', 2, 3, 4)', [INT32_MAX + 1, 2, 3, 4]); CheckLanesF4('var x=f4(1.3, 2.4, 3.5, 98.76)', [1.3, 2.4, 3.5, 98.76]); @@ -253,6 +289,10 @@ CheckI4('', 'var x=i4(1,2,3,4); x=i4(5,6,7,8)', [5, 6, 7, 8]); CheckI4('', 'var x=i4(1,2,3,4); var c=6; x=i4(5,c|0,7,8)', [5, 6, 7, 8]); CheckI4('', 'var x=i4(8,7,6,5); x=i4(e(x,3)|0,e(x,2)|0,e(x,1)|0,e(x,0)|0)', [5, 6, 7, 8]); +CheckU4('', 'var x=u4(1,2,3,4); x=u4(5,6,7,4000000000)', [5, 6, 7, 4000000000]); +CheckU4('', 'var x=u4(1,2,3,4); var c=6; x=u4(5,c|0,7,8)', [5, 6, 7, 8]); +CheckU4('', 'var x=u4(8,7,6,5); x=u4(e(x,3)|0,e(x,2)|0,e(x,1)|0,e(x,0)|0)', [5, 6, 7, 8]); + assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3,4); var c=4; x=f4(1,2,3,c);} return f"); assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3,4); var c=4; x=f4(1.,2.,3.,c);} return f"); assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3,4); var c=4.; x=f4(1,2,3,c);} return f"); @@ -281,6 +321,8 @@ assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3,4); var assertAsmTypeFail('glob', USE_ASM + F32 + I32 + "function f() {var x=f4(1,2,3,4); var y=i4(1,2,3,4); x=1?x:y;} return f"); assertAsmTypeFail('glob', USE_ASM + F32 + I32 + "function f() {var x=f4(1,2,3,4); var y=i4(1,2,3,4); x=1?y:y;} return f"); assertAsmTypeFail('glob', USE_ASM + B32 + I32 + "function f() {var x=b4(1,2,3,4); var y=i4(1,2,3,4); x=1?y:y;} return f"); +assertAsmTypeFail('glob', USE_ASM + U32 + I32 + "function f() {var x=u4(1,2,3,4); var y=i4(1,2,3,4); x=1?y:y;} return f"); +assertAsmTypeFail('glob', USE_ASM + U32 + I32 + "function f() {var x=i4(1,2,3,4); var y=u4(1,2,3,4); x=1?y:y;} return f"); CheckF4('', 'var x=f4(1,2,3,4); var y=f4(4,3,2,1); x=3?y:x', [4, 3, 2, 1]); assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + "function f(x) {x=x|0; var v=f4(1,2,3,4); var w=f4(5,6,7,8); return cf4(x?w:v);} return f"), this)(1), [5,6,7,8]); @@ -292,6 +334,10 @@ assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f(x) {x=x assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f(v) {v=ci4(v); var w=i4(5,6,7,8); return ci4(4?w:v);} return f"), this)(SIMD.Int32x4(1,2,3,4)), [5,6,7,8]); assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f(v, x) {v=ci4(v); x=x|0; var w=i4(5,6,7,8); return ci4(x?w:v);} return f"), this)(SIMD.Int32x4(1,2,3,4), 0), [1,2,3,4]); +// Unsigned SIMD types can't be function arguments or return values. +assertAsmTypeFail('glob', USE_ASM + U32 + CU32 + "function f(x) {x=cu4(x);} return f"); +assertAsmTypeFail('glob', USE_ASM + U32 + CU32 + "function f() {x=u4(0,0,0,0); return cu4(x);} return f"); + // 1.3.4 Return values assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + "function f() {var x=1; return ci4(x)} return f"); assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + "function f() {var x=1; return ci4(x + x)} return f"); @@ -395,11 +441,15 @@ assertAsmTypeFail('glob', USE_ASM + F32 + "var g=f4(1., 2., 3., 4.); var f32=glo assertAsmTypeFail('glob', USE_ASM + F32 + I32 + CI32 + "var g=f4(1., 2., 3., 4.); function f() {var x=i4(1,2,3,4); x=ci4(g);} return f"); assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CF32 + "var g=i4(1,2,3,4); function f() {var x=f4(1.,2.,3.,4.); x=cf4(g);} return f"); +assertAsmTypeFail('glob', USE_ASM + U32 + I32 + CI32 + "var g=u4(1,2,3,4); function f() {var x=i4(1,2,3,4); x=ci4(g);} return f"); assertAsmTypeFail('glob', USE_ASM + I32 + "var g=0; function f() {var x=i4(1,2,3,4); x=g|0;} return f"); assertAsmTypeFail('glob', USE_ASM + I32 + "var g=0.; function f() {var x=i4(1,2,3,4); x=+g;} return f"); assertAsmTypeFail('glob', USE_ASM + I32 + "var f32=glob.Math.fround; var g=f32(0.); function f() {var x=i4(1,2,3,4); x=f32(g);} return f"); +// Unsigned SIMD globals are not allowed. +assertAsmTypeFail('glob', USE_ASM + U32 + "var g=u4(0,0,0,0); function f() {var x=u4(1,2,3,4); x=g;} return f"); + assertAsmTypeFail('glob', USE_ASM + F32 + "var g=0; function f() {var x=f4(0.,0.,0.,0.); x=g|0;} return f"); assertAsmTypeFail('glob', USE_ASM + F32 + "var g=0.; function f() {var x=f4(0.,0.,0.,0.); x=+g;} return f"); assertAsmTypeFail('glob', USE_ASM + F32 + "var f32=glob.Math.fround; var g=f32(0.); function f() {var x=f4(0.,0.,0.,0.); x=f32(g);} return f"); @@ -447,6 +497,9 @@ assertEq(SIMD.Int32x4.extractLane(Int32x4, 3), 4); for (var v of [1, {}, "totally legit SIMD variable", SIMD.Float32x4(1,2,3,4)]) assertCaught(asmCompile('glob', 'ffi', USE_ASM + I32 + CI32 + "var g=ci4(ffi.g); function f() {return ci4(g)} return f"), this, {g: v}); +// Unsigned SIMD globals are not allowed. +assertAsmTypeFail('glob', 'ffi', USE_ASM + U32 + CU32 + "var g=cu4(ffi.g); function f() {} return f"); + var Float32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + F32 + CF32 + "var g=cf4(ffi.g); function f() {return cf4(g)} return f"), this, {g: SIMD.Float32x4(1,2,3,4)})(); assertEq(SIMD.Float32x4.extractLane(Float32x4, 0), 1); assertEq(SIMD.Float32x4.extractLane(Float32x4, 1), 2); @@ -492,6 +545,8 @@ assertAsmTypeFail('glob', USE_ASM + "var g = 3; var add = g.add; return {}"); assertAsmTypeFail('glob', USE_ASM + I32 + "var func = i4.doTheHarlemShake; return {}"); assertAsmTypeFail('glob', USE_ASM + I32 + "var div = i4.div; return {}"); assertAsmTypeFail('glob', USE_ASM + "var f32 = glob.Math.fround; var i4a = f32.add; return {}"); +// Operation exists, but in a different type. +assertAsmTypeFail('glob', USE_ASM + I32 + "var func = i4.fromUint32x4; return {}"); // 2.2 Linking assertAsmLinkAlwaysFail(asmCompile('glob', USE_ASM + I32 + I32A + "function f() {} return f"), {}); @@ -519,6 +574,7 @@ assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4 assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); var y=4; x=i4a(x, y);} return f"); assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(0,0,0,0); var y=4; x=i4a(y, y);} return f"); assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(0,0,0,0); var y=4; y=i4a(x, x);} return f"); +assertAsmTypeFail('glob', USE_ASM + I32 + I32A + U32 + "function f() {var x=i4(0,0,0,0); var y=u4(1,2,3,4); y=i4a(x, y);} return f"); assertAsmTypeFail('glob', USE_ASM + I32 + F32 + I32A + "function f() {var x=i4(0,0,0,0); var y=f4(4,3,2,1); x=i4a(x, y);} return f"); assertAsmTypeFail('glob', USE_ASM + I32 + F32 + I32A + "function f() {var x=i4(0,0,0,0); var y=f4(4,3,2,1); y=i4a(x, y);} return f"); assertAsmTypeFail('glob', USE_ASM + I32 + F32 + I32A + "function f() {var x=i4(0,0,0,0); var y=f4(4,3,2,1); y=i4a(x, x);} return f"); @@ -535,6 +591,10 @@ CheckI4(I32A, 'var x=i4(1,2,3,4); x=i4a(x,x)', [2,4,6,8]); CheckI4(I32A, 'var x=i4(' + INT32_MAX + ',2,3,4); var y=i4(1,1,0,3); x=i4a(x,y)', [INT32_MIN,3,3,7]); CheckI4(I32A, 'var x=i4(' + INT32_MAX + ',2,3,4); var y=i4(1,1,0,3); x=ci4(i4a(x,y))', [INT32_MIN,3,3,7]); +CheckU4(U32A, 'var z=u4(1,2,3,4); var y=u4(0,1,0,3); var x=u4(0,0,0,0); x=u4a(z,y)', [1,3,3,7]); +CheckU4(U32A, 'var x=u4(2,3,4,5); var y=u4(0,1,0,3); x=u4a(x,y)', [2,4,4,8]); +CheckU4(U32A, 'var x=u4(1,2,3,4); x=u4a(x,x)', [2,4,6,8]); + CheckF4(F32A, 'var x=f4(1,2,3,4); x=f4a(x,x)', [2,4,6,8]); CheckF4(F32A, 'var x=f4(1,2,3,4); var y=f4(4,3,5,2); x=f4a(x,y)', [5,5,8,6]); CheckF4(F32A, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=f4a(x,y)', [Math.fround(13.37) + 4,5,8,6]); @@ -547,6 +607,12 @@ CheckI4(I32S, 'var x=i4(1,2,3,4); x=i4s(x,x)', [0,0,0,0]); CheckI4(I32S, 'var x=i4(' + INT32_MIN + ',2,3,4); var y=i4(1,1,0,3); x=i4s(x,y)', [INT32_MAX,1,3,1]); CheckI4(I32S, 'var x=i4(' + INT32_MIN + ',2,3,4); var y=i4(1,1,0,3); x=ci4(i4s(x,y))', [INT32_MAX,1,3,1]); +CheckU4(U32S, 'var x=u4(1,2,3,4); var y=u4(-1,1,0,2); x=u4s(x,y)', [2,1,3,2]); +CheckU4(U32S, 'var x=u4(5,4,3,2); var y=u4(1,2,3,4); x=u4s(x,y)', [4,2,0,-2>>>0]); +CheckU4(U32S, 'var x=u4(1,2,3,4); x=u4s(x,x)', [0,0,0,0]); +CheckU4(U32S, 'var x=u4(' + INT32_MIN + ',2,3,4); var y=u4(1,1,0,3); x=u4s(x,y)', [INT32_MAX,1,3,1]); +CheckU4(U32S, 'var x=u4(' + INT32_MIN + ',2,3,4); var y=u4(1,1,0,3); x=cu4(u4s(x,y))', [INT32_MAX,1,3,1]); + CheckF4(F32S, 'var x=f4(1,2,3,4); x=f4s(x,x)', [0,0,0,0]); CheckF4(F32S, 'var x=f4(1,2,3,4); var y=f4(4,3,5,2); x=f4s(x,y)', [-3,-1,-2,2]); CheckF4(F32S, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=f4s(x,y)', [Math.fround(13.37) - 4,-1,-2,2]); @@ -620,6 +686,16 @@ function CheckUnaryI4(op, checkFunc) { } } +function CheckUnaryU4(op, checkFunc) { + var _ = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32U32 + U32 + U32I32 + + 'var op=u4.' + op + '; function f(x){x=ci4(x); return ci4(i4u4(op(u4i4(x)))); } return f'), this); + return function(input) { + var simd = SIMD.Int32x4(input[0], input[1], input[2], input[3]); + var res = SIMD.Uint32x4.fromInt32x4Bits(_(simd)); + assertEqX4(res, input.map(checkFunc).map(function(x) { return x >>> 0 })); + } +} + function CheckUnaryB4(op, checkFunc) { var _ = asmLink(asmCompile('glob', USE_ASM + B32 + CB32 + 'var op=b4.' + op + '; function f(x){x=cb4(x); return cb4(op(x)); } return f'), this); return function(input) { @@ -631,6 +707,9 @@ function CheckUnaryB4(op, checkFunc) { CheckUnaryI4('neg', function(x) { return -x })([1, -2, INT32_MIN, INT32_MAX]); CheckUnaryI4('not', function(x) { return ~x })([1, -2, INT32_MIN, INT32_MAX]); +CheckUnaryU4('neg', function(x) { return -x })([1, -2, INT32_MIN, INT32_MAX]); +CheckUnaryU4('not', function(x) { return ~x })([1, -2, INT32_MIN, INT32_MAX]); + var CheckNotB = CheckUnaryB4('not', function(x) { return !x }); CheckNotB([true, false, true, true]); CheckNotB([true, true, true, true]); @@ -731,6 +810,12 @@ CheckI4(RLI, 'var x = i4(1,2,3,4); x = r(x, 1, 42);', [1, 42, 3, 4]); CheckI4(RLI, 'var x = i4(1,2,3,4); x = r(x, 2, 42);', [1, 2, 42, 4]); CheckI4(RLI, 'var x = i4(1,2,3,4); x = r(x, 3, 42);', [1, 2, 3, 42]); +const RLU = 'var r = u4.replaceLane;'; +CheckU4(RLU, 'var x = u4(1,2,3,4); x = r(x, 0, 42);', [42, 2, 3, 4]); +CheckU4(RLU, 'var x = u4(1,2,3,4); x = r(x, 1, 42);', [1, 42, 3, 4]); +CheckU4(RLU, 'var x = u4(1,2,3,4); x = r(x, 2, 42);', [1, 2, 42, 4]); +CheckU4(RLU, 'var x = u4(1,2,3,4); x = r(x, 3, 42);', [1, 2, 3, 42]); + const RLB = 'var r = b4.replaceLane;'; CheckB4(RLB, 'var x = b4(1,1,0,0); x = r(x, 0, 0);', [false, true, false, false]); CheckB4(RLB, 'var x = b4(1,1,0,0); x = r(x, 1, 0);', [true, false, false, false]); @@ -773,6 +858,37 @@ CheckB4(I32+GEI32, 'var x=b4(0,0,0,0); var a=i4(1,2,3,4); var b=i4(-1,1,0,2); x CheckB4(I32+GEI32, 'var x=b4(0,0,0,0); var a=i4(-1,1,0,2); var b=i4(1,2,3,4); x=ge(a,b)', [F, F, F, F]); CheckB4(I32+GEI32, 'var x=b4(0,0,0,0); var a=i4(1,0,3,4); var b=i4(1,1,7,0); x=ge(a,b)', [T, F, F, T]); +const EQU32 = 'var eq = u4.equal'; +const NEU32 = 'var ne = u4.notEqual'; +const LTU32 = 'var lt = u4.lessThan;'; +const LEU32 = 'var le = u4.lessThanOrEqual'; +const GTU32 = 'var gt = u4.greaterThan;'; +const GEU32 = 'var ge = u4.greaterThanOrEqual'; + +CheckB4(U32+EQU32, 'var x=b4(0,0,0,0); var a=u4(1,2,3,4); var b=u4(-1,1,0,2); x=eq(a,b)', [F, F, F, F]); +CheckB4(U32+EQU32, 'var x=b4(0,0,0,0); var a=u4(-1,1,0,2); var b=u4(1,2,3,4); x=eq(a,b)', [F, F, F, F]); +CheckB4(U32+EQU32, 'var x=b4(0,0,0,0); var a=u4(1,0,3,4); var b=u4(1,1,7,0); x=eq(a,b)', [T, F, F, F]); + +CheckB4(U32+NEU32, 'var x=b4(0,0,0,0); var a=u4(1,2,3,4); var b=u4(-1,1,0,2); x=ne(a,b)', [T, T, T, T]); +CheckB4(U32+NEU32, 'var x=b4(0,0,0,0); var a=u4(-1,1,0,2); var b=u4(1,2,3,4); x=ne(a,b)', [T, T, T, T]); +CheckB4(U32+NEU32, 'var x=b4(0,0,0,0); var a=u4(1,0,3,4); var b=u4(1,1,7,0); x=ne(a,b)', [F, T, T, T]); + +CheckB4(U32+LTU32, 'var x=b4(0,0,0,0); var a=u4(1,2,3,4); var b=u4(-1,1,0,2); x=lt(a,b)', [T, F, F, F]); +CheckB4(U32+LTU32, 'var x=b4(0,0,0,0); var a=u4(-1,1,0,2); var b=u4(1,2,3,4); x=lt(a,b)', [F, T, T, T]); +CheckB4(U32+LTU32, 'var x=b4(0,0,0,0); var a=u4(1,0,3,4); var b=u4(1,1,7,0); x=lt(a,b)', [F, T, T, F]); + +CheckB4(U32+LEU32, 'var x=b4(0,0,0,0); var a=u4(1,2,3,4); var b=u4(-1,1,0,2); x=le(a,b)', [T, F, F, F]); +CheckB4(U32+LEU32, 'var x=b4(0,0,0,0); var a=u4(-1,1,0,2); var b=u4(1,2,3,4); x=le(a,b)', [F, T, T, T]); +CheckB4(U32+LEU32, 'var x=b4(0,0,0,0); var a=u4(1,0,3,4); var b=u4(1,1,7,0); x=le(a,b)', [T, T, T, F]); + +CheckB4(U32+GTU32, 'var x=b4(0,0,0,0); var a=u4(1,2,3,4); var b=u4(-1,1,0,2); x=gt(a,b)', [F, T, T, T]); +CheckB4(U32+GTU32, 'var x=b4(0,0,0,0); var a=u4(-1,1,0,2); var b=u4(1,2,3,4); x=gt(a,b)', [T, F, F, F]); +CheckB4(U32+GTU32, 'var x=b4(0,0,0,0); var a=u4(1,0,3,4); var b=u4(1,1,7,0); x=gt(a,b)', [F, F, F, T]); + +CheckB4(U32+GEU32, 'var x=b4(0,0,0,0); var a=u4(1,2,3,4); var b=u4(-1,1,0,2); x=ge(a,b)', [F, T, T, T]); +CheckB4(U32+GEU32, 'var x=b4(0,0,0,0); var a=u4(-1,1,0,2); var b=u4(1,2,3,4); x=ge(a,b)', [T, F, F, F]); +CheckB4(U32+GEU32, 'var x=b4(0,0,0,0); var a=u4(1,0,3,4); var b=u4(1,1,7,0); x=ge(a,b)', [T, F, F, T]); + const LTF32 = 'var lt=f4.lessThan;'; const LEF32 = 'var le=f4.lessThanOrEqual;'; const GTF32 = 'var gt=f4.greaterThan;'; @@ -825,8 +941,13 @@ assertEq(f(SIMD.Int32x4(1,2,3,5)), 0); // Conversions operators const CVTIF = 'var cvt=f4.fromInt32x4;'; const CVTFI = 'var cvt=i4.fromFloat32x4;'; +const CVTUF = 'var cvt=f4.fromUint32x4;'; +const CVTFU = 'var cvt=u4.fromFloat32x4;'; assertAsmTypeFail('glob', USE_ASM + I32 + "var cvt=i4.fromInt32x4; return {}"); +assertAsmTypeFail('glob', USE_ASM + I32 + "var cvt=i4.fromUint32x4; return {}"); +assertAsmTypeFail('glob', USE_ASM + U32 + "var cvt=u4.fromInt32x4; return {}"); +assertAsmTypeFail('glob', USE_ASM + U32 + "var cvt=u4.fromUint32x4; return {}"); assertAsmTypeFail('glob', USE_ASM + F32 + "var cvt=f4.fromFloat32x4; return {}"); assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CVTIF + "function f() {var x=i4(1,2,3,4); x=cvt(x);} return f"); assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CVTIF + "function f() {var x=f4(1,2,3,4); x=cvt(x);} return f"); @@ -835,6 +956,11 @@ var f = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CF32 + CI32 + CVTIF + ' assertEqX4(f(SIMD.Int32x4(1,2,3,4)), [1, 2, 3, 4]); assertEqX4(f(SIMD.Int32x4(0,INT32_MIN,INT32_MAX,-1)), [0, Math.fround(INT32_MIN), Math.fround(INT32_MAX), -1]); +var f = asmLink(asmCompile('glob', USE_ASM + I32 + U32 + U32I32 + F32 + CF32 + CI32 + CVTUF + + 'function f(x){x=ci4(x); var y=f4(0,0,0,0); y=cvt(u4i4(x)); return cf4(y);} return f'), this); +assertEqX4(f(SIMD.Int32x4(1,2,3,4)), [1, 2, 3, 4]); +assertEqX4(f(SIMD.Int32x4(0,INT32_MIN,INT32_MAX,-1)), [0, Math.fround(INT32_MAX+1), Math.fround(INT32_MAX), Math.fround(UINT32_MAX)]); + var f = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + F32 + CF32 + CVTFI + 'function f(x){x=cf4(x); var y=i4(0,0,0,0); y=cvt(x); return ci4(y);} return f'), this); assertEqX4(f(SIMD.Float32x4(1,2,3,4)), [1, 2, 3, 4]); // Test that INT32_MIN (exactly representable as an float32) and the first @@ -849,6 +975,20 @@ assertThrowsInstanceOf(() => f(SIMD.Float32x4(NaN, 0, 0, 0)), RangeError); assertThrowsInstanceOf(() => f(SIMD.Float32x4(Infinity, 0, 0, 0)), RangeError); assertThrowsInstanceOf(() => f(SIMD.Float32x4(-Infinity, 0, 0, 0)), RangeError); +var f = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + U32 + I32U32 + F32 + CF32 + CVTFU + + 'function f(x){x=cf4(x); var y=u4(0,0,0,0); y=cvt(x); return ci4(i4u4(y));} return f'), this); +assertEqX4(f(SIMD.Float32x4(1,2,3,4)), [1, 2, 3, 4]); +// TODO: Test negative numbers > -1. They should truncate to 0. See https://github.com/tc39/ecmascript_simd/issues/315 +assertEqX4(SIMD.Uint32x4.fromInt32x4Bits(f(SIMD.Float32x4(0xffffff00, INT32_MAX+1, -0, 0))), + [0xffffff00, INT32_MAX+1, 0, 0].map(Math.fround)); +// Test boundaries: -1 or less. +assertThrowsInstanceOf(() => f(SIMD.Float32x4(-1, 0, 0, 0)), RangeError); +assertThrowsInstanceOf(() => f(SIMD.Float32x4(Math.pow(2, 32), 0, 0, 0)), RangeError); +// Special values +assertThrowsInstanceOf(() => f(SIMD.Float32x4(NaN, 0, 0, 0)), RangeError); +assertThrowsInstanceOf(() => f(SIMD.Float32x4(Infinity, 0, 0, 0)), RangeError); +assertThrowsInstanceOf(() => f(SIMD.Float32x4(-Infinity, 0, 0, 0)), RangeError); + // Cast operators const CVTIFB = 'var cvt=f4.fromInt32x4Bits;'; const CVTFIB = 'var cvt=i4.fromFloat32x4Bits;'; @@ -903,6 +1043,14 @@ CheckI4(ANDI32, 'var x=i4(42,1337,-1,13); var y=i4(2, 4, 7, 15); x=andd(x,y)', [ CheckI4(ORI32, ' var x=i4(42,1337,-1,13); var y=i4(2, 4, 7, 15); x=orr(x,y)', [42 | 2, 1337 | 4, -1 | 7, 13 | 15]); CheckI4(XORI32, 'var x=i4(42,1337,-1,13); var y=i4(2, 4, 7, 15); x=xorr(x,y)', [42 ^ 2, 1337 ^ 4, -1 ^ 7, 13 ^ 15]); +const ANDU32 = 'var andd=u4.and;'; +const ORU32 = 'var orr=u4.or;'; +const XORU32 = 'var xorr=u4.xor;'; + +CheckU4(ANDU32, 'var x=u4(42,1337,-1,13); var y=u4(2, 4, 7, 15); x=andd(x,y)', [42 & 2, 1337 & 4, (-1 & 7) >>> 0, 13 & 15]); +CheckU4(ORU32, ' var x=u4(42,1337,-1,13); var y=u4(2, 4, 7, 15); x=orr(x,y)', [42 | 2, 1337 | 4, (-1 | 7) >>> 0, 13 | 15]); +CheckU4(XORU32, 'var x=u4(42,1337,-1,13); var y=u4(2, 4, 7, 15); x=xorr(x,y)', [42 ^ 2, 1337 ^ 4, (-1 ^ 7) >>> 0, 13 ^ 15]); + const ANDB32 = 'var andd=b4.and;'; const ORB32 = 'var orr=b4.or;'; const XORB32 = 'var xorr=b4.xor;'; @@ -925,8 +1073,6 @@ assertAsmTypeFail('glob', USE_ASM + F32 + CF32 + NOTF32 + 'function f() {var x=f // Logical ops const LSHI = 'var lsh=i4.shiftLeftByScalar;' const RSHI = 'var rsh=i4.shiftRightByScalar;' -const ARSHI = 'var arsh=i4.shiftRightArithmeticByScalar;' -const URSHI = 'var ursh=i4.shiftRightLogicalByScalar;' assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + F32 + FROUND + LSHI + "function f() {var x=f4(1,2,3,4); return ci4(lsh(x,f32(42)));} return f"); assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + F32 + FROUND + LSHI + "function f() {var x=f4(1,2,3,4); return ci4(lsh(x,42));} return f"); @@ -938,31 +1084,50 @@ var vinput = [0, 1, INT32_MIN, INT32_MAX]; // TODO: What to do for masks > 31? Should we keep only the five low bits of // the mask (JS) or not (x86)? -// Behave as x86 for now, fix when more broadly specified. See also bug 1068028 -function Lsh(i) { if (i > 31) return () => 0; return function(x) { return (x << i) | 0 } } -function Rsh(i) { if (i > 31) return (x) => (x<0)?-1:0; return function(x) { return (x >> i) | 0 } } -function Arsh(i) { if (i > 31) return (x) => (x<0)?-1:0; return function(x) { return (x >> i) | 0 } } -function Ursh(i) { if (i > 31) return () => 0; return function(x) { return (x >>> i) | 0 } } +// See bug 1246800. +function Lsh(i) { if (i > 31) return () => 0; return function(x) { return (x << i) | 0 } } +function Rsh(i) { if (i > 31) return (x) => (x<0)?-1:0; return function(x) { return (x >> i) | 0 } } var asmLsh = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + LSHI + 'function f(x, y){x=x|0;y=y|0; var v=' + input + ';return ci4(lsh(v, x+y))} return f;'), this) var asmRsh = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + RSHI + 'function f(x, y){x=x|0;y=y|0; var v=' + input + ';return ci4(rsh(v, x+y))} return f;'), this) -var asmArsh = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + ARSHI + 'function f(x, y){x=x|0;y=y|0; var v=' + input + ';return ci4(arsh(v, x+y))} return f;'), this) -var asmUrsh = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + URSHI + 'function f(x, y){x=x|0;y=y|0; var v=' + input + ';return ci4(ursh(v, x+y))} return f;'), this) for (var i = 1; i < 64; i++) { CheckI4(LSHI, 'var x=' + input + '; x=lsh(x, ' + i + ')', vinput.map(Lsh(i))); CheckI4(RSHI, 'var x=' + input + '; x=rsh(x, ' + i + ')', vinput.map(Rsh(i))); - CheckI4(ARSHI, 'var x=' + input + '; x=arsh(x, ' + i + ')', vinput.map(Arsh(i))); - CheckI4(URSHI, 'var x=' + input + '; x=ursh(x, ' + i + ')', vinput.map(Ursh(i))); assertEqX4(asmLsh(i, 3), vinput.map(Lsh(i + 3))); assertEqX4(asmRsh(i, 3), vinput.map(Rsh(i + 3))); - assertEqX4(asmArsh(i, 3), vinput.map(Arsh(i + 3))); - assertEqX4(asmUrsh(i, 3), vinput.map(Ursh(i + 3))); +} + +// Same thing for Uint32x4. +const LSHU = 'var lsh=u4.shiftLeftByScalar;' +const RSHU = 'var rsh=u4.shiftRightByScalar;' + +input = 'u4(0, 1, 0x80008000, ' + INT32_MAX + ')'; +vinput = [0, 1, 0x80008000, INT32_MAX]; + +function uLsh(i) { if (i > 31) return () => 0; return function(x) { return (x << i) >>> 0 } } +function uRsh(i) { if (i > 31) return () => 0; return function(x) { return (x >>> i) } } + +// Need to bitcast to Int32x4 before returning result. +asmLsh = asmLink(asmCompile('glob', USE_ASM + U32 + CU32 + LSHU + I32 + CI32 + I32U32 + + 'function f(x, y){x=x|0;y=y|0; var v=' + input + ';return ci4(i4u4(lsh(v, x+y)));} return f;'), this) +asmRsh = asmLink(asmCompile('glob', USE_ASM + U32 + CU32 + RSHU + I32 + CI32 + I32U32 + + 'function f(x, y){x=x|0;y=y|0; var v=' + input + ';return ci4(i4u4(rsh(v, x+y)));} return f;'), this) + +for (var i = 1; i < 64; i++) { + // Constant shifts. + CheckU4(LSHU, 'var x=' + input + '; x=lsh(x, ' + i + ')', vinput.map(uLsh(i))); + CheckU4(RSHU, 'var x=' + input + '; x=rsh(x, ' + i + ')', vinput.map(uRsh(i))); + + // Dynamically computed shifts. The asm function returns a Int32x4. + assertEqX4(SIMD.Uint32x4.fromInt32x4Bits(asmLsh(i, 3)), vinput.map(uLsh(i + 3))); + assertEqX4(SIMD.Uint32x4.fromInt32x4Bits(asmRsh(i, 3)), vinput.map(uRsh(i + 3))); } // Select const I32SEL = 'var i4sel = i4.select;' +const U32SEL = 'var u4sel = u4.select;' const F32SEL = 'var f4sel = f4.select;' assertAsmTypeFail('glob', USE_ASM + I32 + F32 + B32 + CI32 + I32SEL + "function f() {var x=f4(1,2,3,4); return ci4(i4sel(x,x,x));} return f"); @@ -992,8 +1157,14 @@ assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + B32 + F32 + CF32 + F32SEL assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + B32 + F32 + CF32 + F32SEL + "function f() {var m=b4(0,1,0,1); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y)); } return f"), this)(), [5, 2, 7, 4]); assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + B32 + F32 + CF32 + F32SEL + "function f() {var m=b4(0,0,1,1); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y)); } return f"), this)(), [5, 6, 3, 4]); +CheckU4(B32 + U32SEL, "var m=b4(0,0,0,0); var x=u4(1,2,3,4); var y=u4(5,6,7,8); x=u4sel(m,x,y);", [5, 6, 7, 8]); +CheckU4(B32 + U32SEL, "var m=b4(1,1,1,1); var x=u4(1,2,3,4); var y=u4(5,6,7,8); x=u4sel(m,x,y);", [1, 2, 3, 4]); +CheckU4(B32 + U32SEL, "var m=b4(0,1,0,1); var x=u4(1,2,3,4); var y=u4(5,6,7,8); x=u4sel(m,x,y);", [5, 2, 7, 4]); +CheckU4(B32 + U32SEL, "var m=b4(0,0,1,1); var x=u4(1,2,3,4); var y=u4(5,6,7,8); x=u4sel(m,x,y);", [5, 6, 3, 4]); + // Splat const I32SPLAT = 'var splat=i4.splat;' +const U32SPLAT = 'var splat=u4.splat;' const F32SPLAT = 'var splat=f4.splat;' const B32SPLAT = 'var splat=b4.splat;' @@ -1008,6 +1179,8 @@ assertAsmTypeFail('glob', USE_ASM + I32 + I32SPLAT + FROUND + "function f() {var assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32SPLAT + 'function f(){return ci4(splat(42));} return f'), this)(), [42, 42, 42, 42]); assertEqX4(asmLink(asmCompile('glob', USE_ASM + B32 + CB32 + B32SPLAT + 'function f(){return cb4(splat(42));} return f'), this)(), [true, true, true, true]); assertEqX4(asmLink(asmCompile('glob', USE_ASM + B32 + CB32 + B32SPLAT + 'function f(){return cb4(splat(0));} return f'), this)(), [false, false, false, false]); +CheckU4(B32 + U32SPLAT, "var x=u4(1,2,3,4); x=splat(0);", [0, 0, 0, 0]); +CheckU4(B32 + U32SPLAT, "var x=u4(1,2,3,4); x=splat(0xaabbccdd);", [0xaabbccdd, 0xaabbccdd, 0xaabbccdd, 0xaabbccdd]); const l33t = Math.fround(13.37); assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + F32SPLAT + FROUND + 'function f(){return cf4(splat(f32(1)));} return f'), this)(), [1, 1, 1, 1]); @@ -1047,6 +1220,7 @@ var before = Date.now(); for (var i = 0; i < Math.pow(4, 4); i++) { var lanes = [i & 3, (i >> 2) & 3, (i >> 4) & 3, (i >> 6) & 3]; CheckI4('var swizzle=i4.swizzle;', 'var x=i4(1,2,3,4); x=swizzle(x, ' + lanes.join(',') + ')', swizzle([1,2,3,4], lanes)); + CheckU4('var swizzle=u4.swizzle;', 'var x=u4(1,2,3,4); x=swizzle(x, ' + lanes.join(',') + ')', swizzle([1,2,3,4], lanes)); CheckF4('var swizzle=f4.swizzle;', 'var x=f4(1,2,3,4); x=swizzle(x, ' + lanes.join(',') + ')', swizzle([1,2,3,4], lanes)); } DEBUG && print('time for checking all swizzles:', Date.now() - before); @@ -1119,6 +1293,7 @@ const LANE_SELECTORS = [ for (var lanes of LANE_SELECTORS) { CheckI4('var shuffle=i4.shuffle;', 'var x=i4(1,2,3,4); var y=i4(5,6,7,8); x=shuffle(x, y, ' + lanes.join(',') + ')', shuffle([1,2,3,4], [5,6,7,8], lanes)); + CheckU4('var shuffle=u4.shuffle;', 'var x=u4(1,2,3,4); var y=u4(5,6,7,8); x=shuffle(x, y, ' + lanes.join(',') + ')', shuffle([1,2,3,4], [5,6,7,8], lanes)); CheckF4('var shuffle=f4.shuffle;', 'var x=f4(1,2,3,4); var y=f4(5,6,7,8); x=shuffle(x, y, ' + lanes.join(',') + ')', shuffle([1,2,3,4], [5,6,7,8], lanes)); } DEBUG && print('time for checking all shuffles:', Date.now() - before); @@ -1138,11 +1313,13 @@ assertAsmTypeFail('glob', USE_ASM + I32 + "var pow=glob.Math.pow; function f() { // 3.2. FFI calls // Can't pass SIMD arguments to FFI assertAsmTypeFail('glob', 'ffi', USE_ASM + I32 + "var func=ffi.func; function f() {var x=i4(1,2,3,4); func(x);} return f"); +assertAsmTypeFail('glob', 'ffi', USE_ASM + U32 + "var func=ffi.func; function f() {var x=u4(1,2,3,4); func(x);} return f"); assertAsmTypeFail('glob', 'ffi', USE_ASM + F32 + "var func=ffi.func; function f() {var x=f4(1,2,3,4); func(x);} return f"); assertAsmTypeFail('glob', 'ffi', USE_ASM + B32 + "var func=ffi.func; function f() {var x=b4(1,2,3,4); func(x);} return f"); // Can't have FFI return SIMD values assertAsmTypeFail('glob', 'ffi', USE_ASM + I32 + "var func=ffi.func; function f() {var x=i4(1,2,3,4); x=i4(func());} return f"); +assertAsmTypeFail('glob', 'ffi', USE_ASM + U32 + "var func=ffi.func; function f() {var x=u4(1,2,3,4); x=i4(func());} return f"); assertAsmTypeFail('glob', 'ffi', USE_ASM + F32 + "var func=ffi.func; function f() {var x=f4(1,2,3,4); x=f4(func());} return f"); assertAsmTypeFail('glob', 'ffi', USE_ASM + B32 + "var func=ffi.func; function f() {var x=b4(1,2,3,4); x=b4(func());} return f"); diff --git a/js/src/jit-test/tests/wasm/basic.js b/js/src/jit-test/tests/wasm/basic.js index b1de3f9bb36a..3db98b4a1d17 100644 --- a/js/src/jit-test/tests/wasm/basic.js +++ b/js/src/jit-test/tests/wasm/basic.js @@ -46,6 +46,11 @@ assertEq(desc.value(), undefined); wasmEvalText('(module (func) (func) (export "a" 0))'); wasmEvalText('(module (func) (func) (export "a" 1))'); +wasmEvalText('(module (func $a) (func $b) (export "a" $a) (export "b" $b))'); +wasmEvalText('(module (func $a) (func $b) (export "a" $a) (export "b" $b))'); +assertErrorMessage(() => wasmEvalText('(module (func $a) (func) (export "a" $a) (export "b" $b))'), SyntaxError, /function not found/); +assertErrorMessage(() => wasmEvalText('(module (func $foo) (func $foo))'), SyntaxError, /duplicate function/); + assertErrorMessage(() => wasmEvalText('(module (func) (export "a" 1))'), TypeError, /export function index out of range/); assertErrorMessage(() => wasmEvalText('(module (func) (func) (export "a" 2))'), TypeError, /export function index out of range/); @@ -92,6 +97,7 @@ assertErrorMessage(() => wasmEvalText('(module (func (result i64)))'), TypeError assertErrorMessage(() => wasmEvalText('(module (import "a" "b"))', 1), Error, /Second argument, if present, must be an Object/); assertErrorMessage(() => wasmEvalText('(module (import "a" "b"))', null), Error, /Second argument, if present, must be an Object/); +assertErrorMessage(() => wasmEvalText('(module (import $foo "a" "b") (import $foo "a" "b"))'), SyntaxError, /duplicate import/); const noImportObj = /no import object given/; const notObject = /import object field is not an Object/; @@ -121,6 +127,7 @@ wasmEvalText(code, {a:()=>{}, b:{c:()=>{}}, c:()=>{}}); wasmEvalText('(module (import "a" "" (result i32)))', {a: ()=> {}}); wasmEvalText('(module (import "a" "" (result f32)))', {a: ()=> {}}); wasmEvalText('(module (import "a" "" (result f64)))', {a: ()=> {}}); +wasmEvalText('(module (import $foo "a" "" (result f64)))', {a: ()=> {}}); // ---------------------------------------------------------------------------- // memory @@ -221,6 +228,11 @@ assertEq(wasmEvalText('(module (func (result i32) (local i32) (set_local 0 (get_ assertErrorMessage(() => wasmEvalText('(module (func (local i64)))'), TypeError, /NYI/); +assertEq(wasmEvalText('(module (func (param $a i32) (result i32) (get_local $a)) (export "" 0))')(), 0); +assertEq(wasmEvalText('(module (func (param $a i32) (local $b i32) (result i32) (block (set_local $b (get_local $a)) (get_local $b))) (export "" 0))')(42), 42); +assertErrorMessage(() => wasmEvalText('(module (func (param $a i32) (local $a i32)))'), SyntaxError, /duplicate var/); +assertErrorMessage(() => wasmEvalText('(module (func (get_local $a)))'), SyntaxError, /local not found/); + // ---------------------------------------------------------------------------- // blocks @@ -336,3 +348,32 @@ for (bad of [6, 7, 100, Math.pow(2,31)-1, Math.pow(2,31), Math.pow(2,31)+1, Math assertThrowsInstanceOf(() => i2i(bad, 0), RangeError); assertThrowsInstanceOf(() => i2v(bad, 0), RangeError); } + +assertErrorMessage(() => wasmEvalText('(module (type $a (func)) (type $a (func (param i32))))'), SyntaxError, /duplicate signature/); +assertErrorMessage(() => wasmEvalText('(module (type $a (func)) (func (type $b) (i32.const 13)))'), SyntaxError, /signature not found/); +assertErrorMessage(() => wasmEvalText('(module (type $a (func)) (func (call_indirect $c (get_local 0) (i32.const 0))))'), SyntaxError, /signature not found/); + +var {v2i, i2i, i2v} = wasmEvalText(`(module + (type $a (func (result i32))) + (type $b (func (param i32) (result i32))) + (type $c (func (param i32))) + (func $a (type $a) (i32.const 13)) + (func $b (type $a) (i32.const 42)) + (func $c (type $b) (i32.add (get_local 0) (i32.const 1))) + (func $d (type $b) (i32.add (get_local 0) (i32.const 2))) + (func $e (type $b) (i32.add (get_local 0) (i32.const 3))) + (func $f (type $b) (i32.add (get_local 0) (i32.const 4))) + (table $a $b $c $d $e $f) + (func (param i32) (result i32) (call_indirect $a (get_local 0))) + (func (param i32) (param i32) (result i32) (call_indirect $b (get_local 0) (get_local 1))) + (func (param i32) (call_indirect $c (get_local 0) (i32.const 0))) + (export "v2i" 6) + (export "i2i" 7) + (export "i2v" 8) +)`); + +wasmEvalText('(module (func $foo (nop)) (func (call $foo)))'); +wasmEvalText('(module (func (call $foo)) (func $foo (nop)))'); +wasmEvalText('(module (import $bar "a" "") (func (call_import $bar)) (func $foo (nop)))', {a:()=>{}}); +assertErrorMessage(() => wasmEvalText('(module (import "a" "") (func (call_import $abc)))'), SyntaxError, /function not found/); + diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index d2447a19a785..885767b9e985 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -1269,7 +1269,9 @@ GuessPhiType(MPhi* phi, bool* hasInputsWithEmptyTypes) // If we only saw definitions that can be converted into Float32 before and // encounter a Float32 value, promote previous values to Float32 type = MIRType_Float32; - } else if (IsNumberType(type) && IsNumberType(in->type())) { + } else if (IsTypeRepresentableAsDouble(type) && + IsTypeRepresentableAsDouble(in->type())) + { // Specialize phis with int32 and double operands as double. type = MIRType_Double; convertibleToFloat32 &= in->canProduceFloat32(); @@ -1329,7 +1331,9 @@ TypeAnalyzer::propagateSpecialization(MPhi* phi) } // Specialize phis with int32 and double operands as double. - if (IsNumberType(use->type()) && IsNumberType(phi->type())) { + if (IsTypeRepresentableAsDouble(use->type()) && + IsTypeRepresentableAsDouble(phi->type())) + { if (!respecialize(use, MIRType_Double)) return false; continue; @@ -2501,6 +2505,7 @@ IsResumableMIRType(MIRType type) case MIRType_ObjectGroup: case MIRType_Doublex2: // NYI, see also RSimdBox::recover case MIRType_SinCosDouble: + case MIRType_Int64: return false; } MOZ_CRASH("Unknown MIRType."); diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index c6b5c23edc01..a3d11748b21e 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -11110,7 +11110,7 @@ IonBuilder::jsop_getprop(PropertyName* name) // Try to emit a shared stub. trackOptimizationAttempt(TrackedStrategy::GetProp_SharedCache); - if (!getPropTrySharedStub(&emitted, obj) || emitted) + if (!getPropTrySharedStub(&emitted, obj, types) || emitted) return emitted; // Emit a call. @@ -12050,7 +12050,7 @@ IonBuilder::getPropTryCache(bool* emitted, MDefinition* obj, PropertyName* name, } bool -IonBuilder::getPropTrySharedStub(bool* emitted, MDefinition* obj) +IonBuilder::getPropTrySharedStub(bool* emitted, MDefinition* obj, TemporaryTypeSet* types) { MOZ_ASSERT(*emitted == false); @@ -12066,6 +12066,15 @@ IonBuilder::getPropTrySharedStub(bool* emitted, MDefinition* obj) if (!resumeAfter(stub)) return false; + // Due to inlining, it's possible the observed TypeSet is non-empty, + // even though we know |obj| is null/undefined and the MCallGetProperty + // will throw. Don't push a TypeBarrier in this case, to avoid + // inlining the following (unreachable) JSOP_CALL. + if (*pc != JSOP_CALLPROP || !IsNullOrUndefined(obj->type())) { + if (!pushTypeBarrier(stub, types, BarrierKind::TypeSet)) + return false; + } + *emitted = true; return true; } diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index 296883bf9978..91a19eb23ea3 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -457,7 +457,7 @@ class IonBuilder TemporaryTypeSet* types); bool getPropTryCache(bool* emitted, MDefinition* obj, PropertyName* name, BarrierKind barrier, TemporaryTypeSet* types); - bool getPropTrySharedStub(bool* emitted, MDefinition* obj); + bool getPropTrySharedStub(bool* emitted, MDefinition* obj, TemporaryTypeSet* types); // jsop_setprop() helpers. bool setPropTryCommonSetter(bool* emitted, MDefinition* obj, diff --git a/js/src/jit/IonTypes.h b/js/src/jit/IonTypes.h index ddf388479c1a..a78e1ab8bd8e 100644 --- a/js/src/jit/IonTypes.h +++ b/js/src/jit/IonTypes.h @@ -399,6 +399,7 @@ enum MIRType MIRType_Null, MIRType_Boolean, MIRType_Int32, + MIRType_Int64, MIRType_Double, MIRType_Float32, MIRType_String, @@ -504,6 +505,8 @@ StringFromMIRType(MIRType type) return "Bool"; case MIRType_Int32: return "Int32"; + case MIRType_Int64: + return "Int64"; case MIRType_Double: return "Double"; case MIRType_Float32: @@ -557,7 +560,18 @@ StringFromMIRType(MIRType type) static inline bool IsNumberType(MIRType type) { - return type == MIRType_Int32 || type == MIRType_Double || type == MIRType_Float32; + return type == MIRType_Int32 || + type == MIRType_Double || + type == MIRType_Float32 || + type == MIRType_Int64; +} + +static inline bool +IsTypeRepresentableAsDouble(MIRType type) +{ + return type == MIRType_Int32 || + type == MIRType_Double || + type == MIRType_Float32; } static inline bool diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index e50588db6d58..c68fc3256b02 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -1280,7 +1280,7 @@ IonBuilder::inlineMathPowHelper(MDefinition* lhs, MDefinition* rhs, MIRType outp // Optimize some constant powers. if (rhs->isConstant()) { - double pow = rhs->toConstant()->toNumber(); + double pow = rhs->toConstant()->numberToDouble(); // Math.pow(x, 0.5) is a sqrt with edge-case detection. if (pow == 0.5) { @@ -1486,7 +1486,7 @@ IonBuilder::inlineMathMinMax(CallInfo& callInfo, bool max) // Don't force a double MMinMax for arguments that would be a NOP // when doing an integer MMinMax. if (arg->isConstant()) { - double cte = arg->toConstant()->toNumber(); + double cte = arg->toConstant()->numberToDouble(); // min(int32, cte >= INT32_MAX) = int32 if (cte >= INT32_MAX && !max) break; @@ -3165,10 +3165,6 @@ IonBuilder::inlineSimd(CallInfo& callInfo, JSFunction* target, SimdType type) return inlineSimdShift(callInfo, native, MSimdShift::lsh, type); case SimdOperation::Fn_shiftRightByScalar: return inlineSimdShift(callInfo, native, MSimdShift::rshForSign(GetSimdSign(type)), type); - case SimdOperation::Fn_shiftRightArithmeticByScalar: - return inlineSimdShift(callInfo, native, MSimdShift::rsh, type); - case SimdOperation::Fn_shiftRightLogicalByScalar: - return inlineSimdShift(callInfo, native, MSimdShift::ursh, type); // Boolean unary. case SimdOperation::Fn_allTrue: @@ -3647,9 +3643,9 @@ IonBuilder::inlineSimdAnyAllTrue(CallInfo& callInfo, bool IsAllTrue, JSNative na MUnaryInstruction* ins; if (IsAllTrue) - ins = MSimdAllTrue::New(alloc(), arg); + ins = MSimdAllTrue::New(alloc(), arg, MIRType_Boolean); else - ins = MSimdAnyTrue::New(alloc(), arg); + ins = MSimdAnyTrue::New(alloc(), arg, MIRType_Boolean); current->add(ins); current->push(ins); diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index a76370a55fe9..5f633373609a 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -85,7 +85,8 @@ EvaluateConstantOperands(TempAllocator& alloc, MBinaryInstruction* ins, bool* pt MDefinition* left = ins->getOperand(0); MDefinition* right = ins->getOperand(1); - MOZ_ASSERT(IsNumberType(left->type()) && IsNumberType(right->type())); + MOZ_ASSERT(IsTypeRepresentableAsDouble(left->type())); + MOZ_ASSERT(IsTypeRepresentableAsDouble(right->type())); if (!left->isConstant() || !right->isConstant()) return nullptr; @@ -114,25 +115,25 @@ EvaluateConstantOperands(TempAllocator& alloc, MBinaryInstruction* ins, bool* pt ret.setNumber(uint32_t(lhs->toInt32()) >> (rhs->toInt32() & 0x1F)); break; case MDefinition::Op_Add: - ret.setNumber(lhs->toNumber() + rhs->toNumber()); + ret.setNumber(lhs->numberToDouble() + rhs->numberToDouble()); break; case MDefinition::Op_Sub: - ret.setNumber(lhs->toNumber() - rhs->toNumber()); + ret.setNumber(lhs->numberToDouble() - rhs->numberToDouble()); break; case MDefinition::Op_Mul: - ret.setNumber(lhs->toNumber() * rhs->toNumber()); + ret.setNumber(lhs->numberToDouble() * rhs->numberToDouble()); break; case MDefinition::Op_Div: if (ins->toDiv()->isUnsigned()) ret.setInt32(rhs->isInt32(0) ? 0 : uint32_t(lhs->toInt32()) / uint32_t(rhs->toInt32())); else - ret.setNumber(NumberDiv(lhs->toNumber(), rhs->toNumber())); + ret.setNumber(NumberDiv(lhs->numberToDouble(), rhs->numberToDouble())); break; case MDefinition::Op_Mod: if (ins->toMod()->isUnsigned()) ret.setInt32(rhs->isInt32(0) ? 0 : uint32_t(lhs->toInt32()) % uint32_t(rhs->toInt32())); else - ret.setNumber(NumberMod(lhs->toNumber(), rhs->toNumber())); + ret.setNumber(NumberMod(lhs->numberToDouble(), rhs->numberToDouble())); break; default: MOZ_CRASH("NYI"); @@ -166,7 +167,7 @@ EvaluateExactReciprocal(TempAllocator& alloc, MDiv* ins) return nullptr; int32_t num; - if (!mozilla::NumberIsInt32(right->toConstant()->toNumber(), &num)) + if (!mozilla::NumberIsInt32(right->toConstant()->numberToDouble(), &num)) return nullptr; // check if rhs is a power of two @@ -670,6 +671,12 @@ MConstant::NewFloat32(TempAllocator& alloc, double d) return new(alloc) MConstant(float(d)); } +MConstant* +MConstant::NewInt64(TempAllocator& alloc, int64_t i) +{ + return new(alloc) MConstant(i); +} + MConstant* MConstant::NewAsmJS(TempAllocator& alloc, const Value& v, MIRType type) { @@ -809,6 +816,13 @@ MConstant::MConstant(float f) setMovable(); } +MConstant::MConstant(int64_t i) +{ + setResultType(MIRType_Int64); + payload_.i64 = i; + setMovable(); +} + #ifdef DEBUG void MConstant::assertInitializedPayload() const @@ -825,6 +839,7 @@ MConstant::assertInitializedPayload() const MOZ_ASSERT((payload_.asBits >> 1) == 0); break; case MIRType_Double: + case MIRType_Int64: break; case MIRType_String: case MIRType_Object: @@ -941,7 +956,7 @@ MConstant::printOpcode(GenericPrinter& out) const bool MConstant::canProduceFloat32() const { - if (!IsNumberType(type())) + if (!isTypeRepresentableAsDouble()) return false; if (type() == MIRType_Int32) @@ -1067,7 +1082,7 @@ MSimdValueX4::foldsTo(TempAllocator& alloc) case MIRType_Float32x4: { float a[4]; for (size_t i = 0; i < 4; ++i) - a[i] = getOperand(i)->toConstant()->toNumber(); + a[i] = getOperand(i)->toConstant()->numberToDouble(); cst = SimdConstant::CreateX4(a); break; } @@ -1103,7 +1118,7 @@ MSimdSplatX4::foldsTo(TempAllocator& alloc) break; } case MIRType_Float32x4: { - float v = op->toConstant()->toNumber(); + float v = op->toConstant()->numberToDouble(); cst = SimdConstant::SplatX4(v); break; } @@ -1446,10 +1461,10 @@ MDefinition* MMathFunction::foldsTo(TempAllocator& alloc) { MDefinition* input = getOperand(0); - if (!input->isConstant() || !input->toConstant()->isNumber()) + if (!input->isConstant() || !input->toConstant()->isTypeRepresentableAsDouble()) return this; - double in = input->toConstant()->toNumber(); + double in = input->toConstant()->numberToDouble(); double out; switch (function_) { case Log: @@ -2017,7 +2032,7 @@ MPhi::foldsTernary() // If testArg is an int32 type we can: // - fold testArg ? testArg : 0 to testArg // - fold testArg ? 0 : testArg to 0 - if (testArg->type() == MIRType_Int32 && c->toNumber() == 0) { + if (testArg->type() == MIRType_Int32 && c->numberToDouble() == 0) { // When folding to the constant we need to hoist it. if (trueDef == c && !c->block()->dominates(block())) c->block()->moveBefore(pred->lastIns(), c); @@ -2159,7 +2174,7 @@ jit::MergeTypes(MIRType* ptype, TemporaryTypeSet** ptypeSet, if (newTypeSet && newTypeSet->empty()) return true; if (newType != *ptype) { - if (IsNumberType(newType) && IsNumberType(*ptype)) { + if (IsTypeRepresentableAsDouble(newType) && IsTypeRepresentableAsDouble(*ptype)) { *ptype = MIRType_Double; } else if (*ptype != MIRType_Value) { if (!*ptypeSet) { @@ -2393,7 +2408,7 @@ IsConstant(MDefinition* def, double v) if (!def->isConstant()) return false; - return NumbersAreIdentical(def->toConstant()->toNumber(), v); + return NumbersAreIdentical(def->toConstant()->numberToDouble(), v); } MDefinition* @@ -2807,11 +2822,14 @@ MMinMax::foldsTo(TempAllocator& alloc) // Directly apply math utility to compare the rhs() and lhs() when // they are both constants. if (lhs()->isConstant() && rhs()->isConstant()) { - if (!lhs()->toConstant()->isNumber() || !rhs()->toConstant()->isNumber()) + if (!lhs()->toConstant()->isTypeRepresentableAsDouble() || + !rhs()->toConstant()->isTypeRepresentableAsDouble()) + { return this; + } - double lnum = lhs()->toConstant()->toNumber(); - double rnum = rhs()->toConstant()->toNumber(); + double lnum = lhs()->toConstant()->numberToDouble(); + double rnum = rhs()->toConstant()->numberToDouble(); double result; if (isMax()) result = js::math_max_impl(lnum, rnum); @@ -2837,7 +2855,10 @@ MMinMax::foldsTo(TempAllocator& alloc) if (operand->isToDouble() && operand->getOperand(0)->type() == MIRType_Int32) { // min(int32, cte >= INT32_MAX) = int32 - if (constant->isNumber() && constant->toNumber() >= INT32_MAX && !isMax()) { + if (!isMax() && + constant->isTypeRepresentableAsDouble() && + constant->numberToDouble() >= INT32_MAX) + { MLimitedTruncate* limit = MLimitedTruncate::New(alloc, operand->getOperand(0), MDefinition::NoTruncate); block()->insertBefore(this, limit); @@ -2846,7 +2867,10 @@ MMinMax::foldsTo(TempAllocator& alloc) } // max(int32, cte <= INT32_MIN) = int32 - if (constant->isNumber() && constant->toNumber() <= INT32_MIN && isMax()) { + if (isMax() && + constant->isTypeRepresentableAsDouble() && + constant->numberToDouble() <= INT32_MIN) + { MLimitedTruncate* limit = MLimitedTruncate::New(alloc, operand->getOperand(0), MDefinition::NoTruncate); block()->insertBefore(this, limit); @@ -3238,7 +3262,7 @@ MCompare::determineCompareType(JSOp op, MDefinition* left, MDefinition* right) } // Numeric comparisons against a double coerce to double. - if (IsNumberType(lhs) && IsNumberType(rhs)) + if (IsTypeRepresentableAsDouble(lhs) && IsTypeRepresentableAsDouble(rhs)) return Compare_Double; // Any comparison is allowed except strict eq. @@ -3648,7 +3672,7 @@ MToInt32::foldsTo(TempAllocator& alloc) case MIRType_Double: int32_t ival; // Only the value within the range of Int32 can be substituted as constant. - if (mozilla::NumberEqualsInt32(input->toConstant()->toNumber(), &ival)) + if (mozilla::NumberEqualsInt32(input->toConstant()->numberToDouble(), &ival)) return MConstant::New(alloc, Int32Value(ival)); break; default: @@ -3696,8 +3720,8 @@ MToDouble::foldsTo(TempAllocator& alloc) if (input->type() == MIRType_Double) return input; - if (input->isConstant() && input->toConstant()->isNumber()) { - double out = input->toConstant()->toNumber(); + if (input->isConstant() && input->toConstant()->isTypeRepresentableAsDouble()) { + double out = input->toConstant()->numberToDouble(); return MConstant::New(alloc, DoubleValue(out)); } @@ -3718,8 +3742,8 @@ MToFloat32::foldsTo(TempAllocator& alloc) if (input->isToDouble() && input->toToDouble()->input()->type() == MIRType_Float32) return input->toToDouble()->input(); - if (input->isConstant() && input->toConstant()->isNumber()) - return MConstant::NewFloat32(alloc, float(input->toConstant()->toNumber())); + if (input->isConstant() && input->toConstant()->isTypeRepresentableAsDouble()) + return MConstant::NewFloat32(alloc, float(input->toConstant()->numberToDouble())); return this; } @@ -3740,8 +3764,8 @@ MDefinition* MClampToUint8::foldsTo(TempAllocator& alloc) { if (MConstant* inputConst = input()->maybeConstantValue()) { - if (inputConst->isNumber()) { - int32_t clamped = ClampDoubleToUint8(inputConst->toNumber()); + if (inputConst->isTypeRepresentableAsDouble()) { + int32_t clamped = ClampDoubleToUint8(inputConst->numberToDouble()); return MConstant::New(alloc, Int32Value(clamped)); } } @@ -4083,29 +4107,29 @@ MCompare::evaluateConstantOperands(TempAllocator& alloc, bool* result) return true; } - if (!lhs->isNumber() || !rhs->isNumber()) + if (!lhs->isTypeRepresentableAsDouble() || !rhs->isTypeRepresentableAsDouble()) return false; switch (jsop_) { case JSOP_LT: - *result = (lhs->toNumber() < rhs->toNumber()); + *result = (lhs->numberToDouble() < rhs->numberToDouble()); break; case JSOP_LE: - *result = (lhs->toNumber() <= rhs->toNumber()); + *result = (lhs->numberToDouble() <= rhs->numberToDouble()); break; case JSOP_GT: - *result = (lhs->toNumber() > rhs->toNumber()); + *result = (lhs->numberToDouble() > rhs->numberToDouble()); break; case JSOP_GE: - *result = (lhs->toNumber() >= rhs->toNumber()); + *result = (lhs->numberToDouble() >= rhs->numberToDouble()); break; case JSOP_STRICTEQ: // Fall through. case JSOP_EQ: - *result = (lhs->toNumber() == rhs->toNumber()); + *result = (lhs->numberToDouble() == rhs->numberToDouble()); break; case JSOP_STRICTNE: // Fall through. case JSOP_NE: - *result = (lhs->toNumber() != rhs->toNumber()); + *result = (lhs->numberToDouble() != rhs->numberToDouble()); break; default: return false; diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 5cabe59a3f75..2365138fb509 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -1371,6 +1371,7 @@ class MConstant : public MNullaryInstruction union { bool b; int32_t i32; + int64_t i64; float f; double d; JSString* str; @@ -1396,12 +1397,14 @@ class MConstant : public MNullaryInstruction MConstant(const Value& v, CompilerConstraintList* constraints); explicit MConstant(JSObject* obj); explicit MConstant(float f); + explicit MConstant(int64_t i); public: INSTRUCTION_HEADER(Constant) static MConstant* New(TempAllocator& alloc, const Value& v, CompilerConstraintList* constraints = nullptr); static MConstant* NewFloat32(TempAllocator& alloc, double d); + static MConstant* NewInt64(TempAllocator& alloc, int64_t i); static MConstant* NewAsmJS(TempAllocator& alloc, const Value& v, MIRType type); static MConstant* NewConstraintlessObject(TempAllocator& alloc, JSObject* v); @@ -1458,6 +1461,10 @@ class MConstant : public MNullaryInstruction MOZ_ASSERT(type() == MIRType_Int32); return payload_.i32; } + int64_t toInt64() const { + MOZ_ASSERT(type() == MIRType_Int64); + return payload_.i64; + } bool isInt32(int32_t i) const { return type() == MIRType_Int32 && payload_.i32 == i; } @@ -1488,15 +1495,15 @@ class MConstant : public MNullaryInstruction return nullptr; } - bool isNumber() const { - return IsNumberType(type()); + bool isTypeRepresentableAsDouble() const { + return IsTypeRepresentableAsDouble(type()); } - double toNumber() const { + double numberToDouble() const { + MOZ_ASSERT(isTypeRepresentableAsDouble()); if (type() == MIRType_Int32) return toInt32(); if (type() == MIRType_Double) return toDouble(); - MOZ_ASSERT(type() == MIRType_Float32); return toFloat32(); } @@ -1532,17 +1539,6 @@ class MSimdValueX4 return new(alloc) MSimdValueX4(type, x, y, z, w); } - static MSimdValueX4* NewAsmJS(TempAllocator& alloc, MIRType type, MDefinition* x, - MDefinition* y, MDefinition* z, MDefinition* w) - { - mozilla::DebugOnly laneType = SimdTypeToLaneArgumentType(type); - MOZ_ASSERT(laneType == x->type()); - MOZ_ASSERT(laneType == y->type()); - MOZ_ASSERT(laneType == z->type()); - MOZ_ASSERT(laneType == w->type()); - return MSimdValueX4::New(alloc, type, x, y, z, w); - } - bool canConsumeFloat32(MUse* use) const override { return SimdTypeToLaneType(type()) == MIRType_Float32; } @@ -1577,12 +1573,6 @@ class MSimdSplatX4 public: INSTRUCTION_HEADER(SimdSplatX4) - static MSimdSplatX4* NewAsmJS(TempAllocator& alloc, MDefinition* v, MIRType type) - { - MOZ_ASSERT(SimdTypeToLaneArgumentType(type) == v->type()); - return new(alloc) MSimdSplatX4(type, v); - } - static MSimdSplatX4* New(TempAllocator& alloc, MDefinition* v, MIRType type) { return new(alloc) MSimdSplatX4(type, v); @@ -1675,11 +1665,6 @@ class MSimdConvert public: INSTRUCTION_HEADER(SimdConvert) - static MSimdConvert* NewAsmJS(TempAllocator& alloc, MDefinition* obj, MIRType toType) - { - // AsmJS only has signed integer vectors for now. - return new(alloc) MSimdConvert(obj, toType, SimdSign::Signed); - } static MSimdConvert* New(TempAllocator& alloc, MDefinition* obj, MIRType toType, SimdSign sign) { @@ -1727,10 +1712,6 @@ class MSimdReinterpretCast public: INSTRUCTION_HEADER(SimdReinterpretCast) - static MSimdReinterpretCast* NewAsmJS(TempAllocator& alloc, MDefinition* obj, MIRType toType) - { - return new(alloc) MSimdReinterpretCast(obj, toType); - } static MSimdReinterpretCast* New(TempAllocator& alloc, MDefinition* obj, MIRType toType) { @@ -1788,15 +1769,6 @@ class MSimdExtractElement public: INSTRUCTION_HEADER(SimdExtractElement) - static MSimdExtractElement* NewAsmJS(TempAllocator& alloc, MDefinition* obj, MIRType type, - SimdLane lane) - { - // Only signed integer types in AsmJS so far. - SimdSign sign = - IsIntegerSimdType(obj->type()) ? SimdSign::Signed : SimdSign::NotApplicable; - return new (alloc) MSimdExtractElement(obj, type, lane, sign); - } - static MSimdExtractElement* New(TempAllocator& alloc, MDefinition* obj, MIRType scalarType, SimdLane lane, SimdSign sign) { @@ -1845,13 +1817,6 @@ class MSimdInsertElement public: INSTRUCTION_HEADER(SimdInsertElement) - static MSimdInsertElement* NewAsmJS(TempAllocator& alloc, MDefinition* vec, MDefinition* val, - SimdLane lane) - { - MOZ_ASSERT(SimdTypeToLaneArgumentType(vec->type()) == val->type()); - return new(alloc) MSimdInsertElement(vec, val, lane); - } - static MSimdInsertElement* New(TempAllocator& alloc, MDefinition* vec, MDefinition* val, SimdLane lane) { @@ -1915,14 +1880,9 @@ class MSimdAllTrue public: INSTRUCTION_HEADER(SimdAllTrue) - static MSimdAllTrue* NewAsmJS(TempAllocator& alloc, MDefinition* obj) + static MSimdAllTrue* New(TempAllocator& alloc, MDefinition* obj, MIRType type) { - return new(alloc) MSimdAllTrue(obj, MIRType_Int32); - } - - static MSimdAllTrue* New(TempAllocator& alloc, MDefinition* obj) - { - return new(alloc) MSimdAllTrue(obj, MIRType_Boolean); + return new(alloc) MSimdAllTrue(obj, type); } AliasSet getAliasSet() const override { @@ -1954,14 +1914,9 @@ class MSimdAnyTrue public: INSTRUCTION_HEADER(SimdAnyTrue) - static MSimdAnyTrue* NewAsmJS(TempAllocator& alloc, MDefinition* obj) + static MSimdAnyTrue* New(TempAllocator& alloc, MDefinition* obj, MIRType type) { - return new(alloc) MSimdAnyTrue(obj, MIRType_Int32); - } - - static MSimdAnyTrue* New(TempAllocator& alloc, MDefinition* obj) - { - return new(alloc) MSimdAnyTrue(obj, MIRType_Boolean); + return new(alloc) MSimdAnyTrue(obj, type); } AliasSet getAliasSet() const override { @@ -2234,11 +2189,6 @@ class MSimdUnaryArith return new(alloc) MSimdUnaryArith(def, op); } - static MSimdUnaryArith* NewAsmJS(TempAllocator& alloc, MDefinition* def, Operation op) - { - return new(alloc) MSimdUnaryArith(def, op); - } - Operation operation() const { return operation_; } AliasSet getAliasSet() const override { @@ -2300,14 +2250,6 @@ class MSimdBinaryComp public: INSTRUCTION_HEADER(SimdBinaryComp) - static MSimdBinaryComp* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right, - Operation op) - { - // AsmJS only has signed vectors for now. - SimdSign sign = - IsIntegerSimdType(left->type()) ? SimdSign::Signed : SimdSign::NotApplicable; - return new (alloc) MSimdBinaryComp(left, right, op, sign); - } static MSimdBinaryComp* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, Operation op, SimdSign sign) @@ -2405,12 +2347,6 @@ class MSimdBinaryArith return new(alloc) MSimdBinaryArith(left, right, op); } - static MSimdBinaryArith* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right, - Operation op) - { - return New(alloc, left, right, op); - } - AliasSet getAliasSet() const override { return AliasSet::None(); } @@ -2470,12 +2406,6 @@ class MSimdBinaryBitwise return new(alloc) MSimdBinaryBitwise(left, right, op); } - static MSimdBinaryBitwise* NewAsmJS(TempAllocator& alloc, MDefinition* left, - MDefinition* right, Operation op) - { - return new(alloc) MSimdBinaryBitwise(left, right, op); - } - AliasSet getAliasSet() const override { return AliasSet::None(); } @@ -2518,12 +2448,6 @@ class MSimdShift public: INSTRUCTION_HEADER(SimdShift) - static MSimdShift* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right, - Operation op) - { - MOZ_ASSERT(left->type() == MIRType_Int32x4 && right->type() == MIRType_Int32); - return new(alloc) MSimdShift(left, right, op); - } static MSimdShift* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, Operation op) @@ -2580,11 +2504,6 @@ class MSimdSelect public: INSTRUCTION_HEADER(SimdSelect) - static MSimdSelect* NewAsmJS(TempAllocator& alloc, MDefinition* mask, MDefinition* lhs, - MDefinition* rhs) - { - return new(alloc) MSimdSelect(mask, lhs, rhs); - } static MSimdSelect* New(TempAllocator& alloc, MDefinition* mask, MDefinition* lhs, MDefinition* rhs) diff --git a/js/src/jit/RangeAnalysis.cpp b/js/src/jit/RangeAnalysis.cpp index b193eee4e307..f3c7d0ca99f9 100644 --- a/js/src/jit/RangeAnalysis.cpp +++ b/js/src/jit/RangeAnalysis.cpp @@ -198,12 +198,12 @@ RangeAnalysis::addBetaNodes() MConstant* leftConst = left->maybeConstantValue(); MConstant* rightConst = right->maybeConstantValue(); - if (leftConst && leftConst->isNumber()) { - bound = leftConst->toNumber(); + if (leftConst && leftConst->isTypeRepresentableAsDouble()) { + bound = leftConst->numberToDouble(); val = right; jsop = ReverseCompareOp(jsop); - } else if (rightConst && rightConst->isNumber()) { - bound = rightConst->toNumber(); + } else if (rightConst && rightConst->isTypeRepresentableAsDouble()) { + bound = rightConst->numberToDouble(); val = left; } else if (left->type() == MIRType_Int32 && right->type() == MIRType_Int32) { MDefinition* smaller = nullptr; @@ -1291,8 +1291,8 @@ MBeta::computeRange(TempAllocator& alloc) void MConstant::computeRange(TempAllocator& alloc) { - if (isNumber()) { - double d = toNumber(); + if (isTypeRepresentableAsDouble()) { + double d = numberToDouble(); setRange(Range::NewDoubleSingletonRange(alloc, d)); } else if (type() == MIRType_Boolean) { bool b = toBoolean(); @@ -2416,7 +2416,7 @@ MConstant::truncate() MOZ_ASSERT(needTruncation(Truncate)); // Truncate the double to int, since all uses truncates it. - int32_t res = ToInt32(toNumber()); + int32_t res = ToInt32(numberToDouble()); payload_.asBits = 0; payload_.i32 = res; setResultType(MIRType_Int32); diff --git a/js/src/jit/mips32/Lowering-mips32.cpp b/js/src/jit/mips32/Lowering-mips32.cpp index aa9a55795bd9..79349dc1cc34 100644 --- a/js/src/jit/mips32/Lowering-mips32.cpp +++ b/js/src/jit/mips32/Lowering-mips32.cpp @@ -45,7 +45,7 @@ LIRGeneratorMIPS::visitBox(MBox* box) } if (inner->isConstant()) { - defineBox(new(alloc()) LValue(inner->toConstant()->value()), box); + defineBox(new(alloc()) LValue(inner->toConstant()->toJSValue()), box); return; } diff --git a/js/src/jit/shared/CodeGenerator-shared-inl.h b/js/src/jit/shared/CodeGenerator-shared-inl.h index 170875fbd0c2..228365344247 100644 --- a/js/src/jit/shared/CodeGenerator-shared-inl.h +++ b/js/src/jit/shared/CodeGenerator-shared-inl.h @@ -28,7 +28,7 @@ ToInt32(const LAllocation* a) static inline double ToDouble(const LAllocation* a) { - return a->toConstant()->toNumber(); + return a->toConstant()->numberToDouble(); } static inline Register diff --git a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp index 425235d438ef..851608e4cd06 100644 --- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp +++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp @@ -2408,7 +2408,11 @@ CodeGeneratorX86Shared::visitFloat32x4ToUint32x4(LFloat32x4ToUint32x4* ins) masm.vcmpleps(Operand(in), scratch, scratch); masm.vmovmskps(scratch, temp); masm.cmp32(temp, Imm32(15)); - bailoutIf(Assembler::NotEqual, ins->snapshot()); + + if (gen->compilingAsmJS()) + masm.j(Assembler::NotEqual, wasm::JumpTarget::ConversionError); + else + bailoutIf(Assembler::NotEqual, ins->snapshot()); // TODO: If the majority of lanes are A-lanes, it could be faster to compute // A first, use vmovmskps to check for any non-A-lanes and handle them in @@ -2443,7 +2447,11 @@ CodeGeneratorX86Shared::visitFloat32x4ToUint32x4(LFloat32x4ToUint32x4* ins) // the remaining negative lanes in B. masm.vmovmskps(scratch, temp); masm.cmp32(temp, Imm32(0)); - bailoutIf(Assembler::NotEqual, ins->snapshot()); + + if (gen->compilingAsmJS()) + masm.j(Assembler::NotEqual, wasm::JumpTarget::ConversionError); + else + bailoutIf(Assembler::NotEqual, ins->snapshot()); } void diff --git a/js/src/jsapi-tests/testJitDCEinGVN.cpp b/js/src/jsapi-tests/testJitDCEinGVN.cpp index 9d6b13ab44f4..9d3a94921056 100644 --- a/js/src/jsapi-tests/testJitDCEinGVN.cpp +++ b/js/src/jsapi-tests/testJitDCEinGVN.cpp @@ -136,7 +136,7 @@ BEGIN_TEST(testJitDCEinGVN_phi) // c1 should be deleted. for (MInstructionIterator ins = block->begin(); ins != block->end(); ins++) { - CHECK(!ins->isConstant() || (ins->toConstant()->toNumber() != 1.0)); + CHECK(!ins->isConstant() || (ins->toConstant()->numberToDouble() != 1.0)); } return true; } diff --git a/js/src/jsapi-tests/testJitFoldsTo.cpp b/js/src/jsapi-tests/testJitFoldsTo.cpp index ba5278c793bd..4b5e2c0f1a56 100644 --- a/js/src/jsapi-tests/testJitFoldsTo.cpp +++ b/js/src/jsapi-tests/testJitFoldsTo.cpp @@ -42,7 +42,7 @@ BEGIN_TEST(testJitFoldsTo_DivReciprocal) CHECK(op->isMul()); CHECK(op->getOperand(0) == left); CHECK(op->getOperand(1)->isConstant()); - CHECK(op->getOperand(1)->toConstant()->toNumber() == 0.25); + CHECK(op->getOperand(1)->toConstant()->numberToDouble() == 0.25); return true; } END_TEST(testJitFoldsTo_DivReciprocal) @@ -229,7 +229,7 @@ BEGIN_TEST(testJitFoldsTo_UnsignedDiv) // Test that the div got folded to 0. MConstant* op = ret->getOperand(0)->toConstant(); - CHECK(mozilla::NumbersAreIdentical(op->toNumber(), 0.0)); + CHECK(mozilla::NumbersAreIdentical(op->numberToDouble(), 0.0)); return true; } END_TEST(testJitFoldsTo_UnsignedDiv) @@ -254,7 +254,7 @@ BEGIN_TEST(testJitFoldsTo_UnsignedMod) // Test that the mod got folded to 1. MConstant* op = ret->getOperand(0)->toConstant(); - CHECK(mozilla::NumbersAreIdentical(op->toNumber(), 1.0)); + CHECK(mozilla::NumbersAreIdentical(op->numberToDouble(), 1.0)); return true; } END_TEST(testJitFoldsTo_UnsignedMod) diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 0c7afc820744..5e9ff235a65a 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -261,14 +261,20 @@ const AllocKind gc::slotsToThingKind[] = { static_assert(JS_ARRAY_LENGTH(slotsToThingKind) == SLOTS_TO_THING_KIND_LIMIT, "We have defined a slot count for each kind."); -// Assert that SortedArenaList::MinThingSize is <= the real minimum thing size. -#define CHECK_MIN_THING_SIZE_INNER(x_) \ +// Assert that SortedArenaList::MinThingSize and sizeof(FreeSpan) are <= the +// real minimum thing size. Also assert each size is a multiple of CellSize. +#define CHECK_THING_SIZE_INNER(x_) \ static_assert(x_ >= SortedArenaList::MinThingSize, \ - #x_ " is less than SortedArenaList::MinThingSize!"); -#define CHECK_MIN_THING_SIZE(...) { __VA_ARGS__ }; /* Define the array. */ \ - MOZ_FOR_EACH(CHECK_MIN_THING_SIZE_INNER, (), (__VA_ARGS__ UINT32_MAX)) + #x_ " is less than SortedArenaList::MinThingSize!"); \ + static_assert(x_ >= sizeof(FreeSpan), \ + #x_ " is less than sizeof(FreeSpan)"); \ + static_assert(x_ % CellSize == 0, \ + #x_ " not a multiple of CellSize"); -const uint32_t Arena::ThingSizes[] = CHECK_MIN_THING_SIZE( +#define CHECK_THING_SIZE(...) { __VA_ARGS__ }; /* Define the array. */ \ + MOZ_FOR_EACH(CHECK_THING_SIZE_INNER, (), (__VA_ARGS__ 0x20)) + +const uint32_t Arena::ThingSizes[] = CHECK_THING_SIZE( sizeof(JSFunction), /* AllocKind::FUNCTION */ sizeof(FunctionExtended), /* AllocKind::FUNCTION_EXTENDED */ sizeof(JSObject_Slots0), /* AllocKind::OBJECT0 */ @@ -296,8 +302,8 @@ const uint32_t Arena::ThingSizes[] = CHECK_MIN_THING_SIZE( sizeof(jit::JitCode), /* AllocKind::JITCODE */ ); -#undef CHECK_MIN_THING_SIZE_INNER -#undef CHECK_MIN_THING_SIZE +#undef CHECK_THING_SIZE_INNER +#undef CHECK_THING_SIZE #define OFFSET(type) uint32_t(sizeof(ArenaHeader) + (ArenaSize - sizeof(ArenaHeader)) % sizeof(type)) @@ -331,6 +337,38 @@ const uint32_t Arena::FirstThingOffsets[] = { #undef OFFSET +#define COUNT(type) uint32_t((ArenaSize - sizeof(ArenaHeader)) / sizeof(type)) + +const uint32_t Arena::ThingsPerArena[] = { + COUNT(JSFunction), /* AllocKind::FUNCTION */ + COUNT(FunctionExtended), /* AllocKind::FUNCTION_EXTENDED */ + COUNT(JSObject_Slots0), /* AllocKind::OBJECT0 */ + COUNT(JSObject_Slots0), /* AllocKind::OBJECT0_BACKGROUND */ + COUNT(JSObject_Slots2), /* AllocKind::OBJECT2 */ + COUNT(JSObject_Slots2), /* AllocKind::OBJECT2_BACKGROUND */ + COUNT(JSObject_Slots4), /* AllocKind::OBJECT4 */ + COUNT(JSObject_Slots4), /* AllocKind::OBJECT4_BACKGROUND */ + COUNT(JSObject_Slots8), /* AllocKind::OBJECT8 */ + COUNT(JSObject_Slots8), /* AllocKind::OBJECT8_BACKGROUND */ + COUNT(JSObject_Slots12), /* AllocKind::OBJECT12 */ + COUNT(JSObject_Slots12), /* AllocKind::OBJECT12_BACKGROUND */ + COUNT(JSObject_Slots16), /* AllocKind::OBJECT16 */ + COUNT(JSObject_Slots16), /* AllocKind::OBJECT16_BACKGROUND */ + COUNT(JSScript), /* AllocKind::SCRIPT */ + COUNT(LazyScript), /* AllocKind::LAZY_SCRIPT */ + COUNT(Shape), /* AllocKind::SHAPE */ + COUNT(AccessorShape), /* AllocKind::ACCESSOR_SHAPE */ + COUNT(BaseShape), /* AllocKind::BASE_SHAPE */ + COUNT(ObjectGroup), /* AllocKind::OBJECT_GROUP */ + COUNT(JSFatInlineString), /* AllocKind::FAT_INLINE_STRING */ + COUNT(JSString), /* AllocKind::STRING */ + COUNT(JSExternalString), /* AllocKind::EXTERNAL_STRING */ + COUNT(JS::Symbol), /* AllocKind::SYMBOL */ + COUNT(jit::JitCode), /* AllocKind::JITCODE */ +}; + +#undef COUNT + struct js::gc::FinalizePhase { size_t length; @@ -455,9 +493,11 @@ ArenaHeader::unmarkAll() Arena::staticAsserts() { static_assert(JS_ARRAY_LENGTH(ThingSizes) == size_t(AllocKind::LIMIT), - "We haven't defined all thing sizes."); + "We haven't defined all thing sizes."); static_assert(JS_ARRAY_LENGTH(FirstThingOffsets) == size_t(AllocKind::LIMIT), - "We haven't defined all offsets."); + "We haven't defined all offsets."); + static_assert(JS_ARRAY_LENGTH(ThingsPerArena) == size_t(AllocKind::LIMIT), + "We haven't defined all counts."); } void @@ -542,7 +582,7 @@ Arena::finalize(FreeOp* fop, AllocKind thingKind, size_t thingSize) size_t nfree = 0; for (const FreeSpan* span = &newListHead; !span->isEmpty(); span = span->nextSpan()) nfree += span->length(thingSize); - MOZ_ASSERT(nfree + nmarked == thingsPerArena(thingSize)); + MOZ_ASSERT(nfree + nmarked == thingsPerArena(thingKind)); #endif aheader.setFirstFreeSpan(&newListHead); return nmarked; @@ -570,7 +610,7 @@ FinalizeTypedArenas(FreeOp* fop, MOZ_ASSERT_IF(fop->onBackgroundThread(), keepArenas == ArenaLists::KEEP_ARENAS); size_t thingSize = Arena::thingSize(thingKind); - size_t thingsPerArena = Arena::thingsPerArena(thingSize); + size_t thingsPerArena = Arena::thingsPerArena(thingKind); while (ArenaHeader* aheader = *src) { *src = aheader->next; @@ -923,6 +963,7 @@ void Chunk::addArenaToFreeList(JSRuntime* rt, ArenaHeader* aheader) { MOZ_ASSERT(!aheader->allocated()); + MOZ_RELEASE_ASSERT(uintptr_t(info.freeArenasHead) != uintptr_t(UINT64_C(0x4b4b4b4b4b4b4b4b))); aheader->next = info.freeArenasHead; info.freeArenasHead = aheader; ++info.numArenasFreeCommitted; @@ -2032,7 +2073,7 @@ size_t ArenaHeader::countFreeCells() size_t ArenaHeader::countUsedCells() { - return Arena::thingsPerArena(getThingSize()) - countFreeCells(); + return Arena::thingsPerArena(getAllocKind()) - countFreeCells(); } ArenaHeader* @@ -2094,7 +2135,7 @@ ArenaList::pickArenasToRelocate(size_t& arenaTotalOut, size_t& relocTotalOut) } mozilla::DebugOnly lastFreeCells(0); - size_t cellsPerArena = Arena::thingsPerArena((*arenap)->getThingSize()); + size_t cellsPerArena = Arena::thingsPerArena((*arenap)->getAllocKind()); while (*arenap) { ArenaHeader* arena = *arenap; @@ -2255,6 +2296,7 @@ ArenaList::relocateArenas(ArenaHeader* toRelocate, ArenaHeader* relocated, Slice toRelocate = arena->next; RelocateArena(arena, sliceBudget); // Prepend to list of relocated arenas + MOZ_RELEASE_ASSERT(uintptr_t(relocated) != uintptr_t(UINT64_C(0x4b4b4b4b4b4b4b4b))); arena->next = relocated; relocated = arena; stats.count(gcstats::STAT_ARENA_RELOCATED); @@ -2364,7 +2406,7 @@ GCRuntime::relocateArenas(Zone* zone, JS::gcreason::Reason reason, ArenaHeader*& // Check that we did as much compaction as we should have. There // should always be less than one arena's worth of free cells. for (auto i : AllAllocKinds()) { - size_t thingsPerArena = Arena::thingsPerArena(Arena::thingSize(i)); + size_t thingsPerArena = Arena::thingsPerArena(i); if (CanRelocateAllocKind(i)) { ArenaList& al = zone->arenas.arenaLists[i]; size_t freeCells = 0; @@ -2803,6 +2845,8 @@ GCRuntime::protectAndHoldArenas(ArenaHeader* arenaList) ArenaHeader* next = arena->next; if (!next) { // Prepend to hold list before we protect the memory. + MOZ_RELEASE_ASSERT( + uintptr_t(relocatedArenasToRelease) != uintptr_t(UINT64_C(0x4b4b4b4b4b4b4b4b))); arena->next = relocatedArenasToRelease; relocatedArenasToRelease = arenaList; } @@ -2850,7 +2894,7 @@ GCRuntime::releaseRelocatedArenasWithoutUnlocking(ArenaHeader* arenaList, const #if defined(JS_CRASH_DIAGNOSTICS) || defined(JS_GC_ZEAL) JS_POISON(reinterpret_cast(arena->thingsStart(thingKind)), - JS_MOVED_TENURED_PATTERN, Arena::thingsSpan(thingSize)); + JS_MOVED_TENURED_PATTERN, Arena::thingsSpan(thingKind)); #endif releaseArena(aheader, lock); @@ -2936,7 +2980,7 @@ ArenaLists::forceFinalizeNow(FreeOp* fop, AllocKind thingKind, KeepArenasEnum ke return; arenaLists[thingKind].clear(); - size_t thingsPerArena = Arena::thingsPerArena(Arena::thingSize(thingKind)); + size_t thingsPerArena = Arena::thingsPerArena(thingKind); SortedArenaList finalizedSorted(thingsPerArena); auto unlimited = SliceBudget::unlimited(); @@ -3005,7 +3049,7 @@ ArenaLists::backgroundFinalize(FreeOp* fop, ArenaHeader* listHead, ArenaHeader** AllocKind thingKind = listHead->getAllocKind(); Zone* zone = listHead->zone; - size_t thingsPerArena = Arena::thingsPerArena(Arena::thingSize(thingKind)); + size_t thingsPerArena = Arena::thingsPerArena(thingKind); SortedArenaList finalizedSorted(thingsPerArena); auto unlimited = SliceBudget::unlimited(); @@ -3432,7 +3476,7 @@ GCRuntime::sweepBackgroundThings(ZoneList& zones, LifoAlloc& freeBlocks, ThreadT for (unsigned index = 0 ; index < BackgroundFinalizePhases[phase].length ; ++index) { AllocKind kind = BackgroundFinalizePhases[phase].kinds[index]; ArenaHeader* arenas = zone->arenas.arenaListsToSweep[kind]; - MOZ_RELEASE_ASSERT(uintptr_t(arenas) != uintptr_t(-1)); + MOZ_RELEASE_ASSERT(uintptr_t(arenas) != uintptr_t(UINT64_C(0x4b4b4b4b4b4b4b4b))); if (arenas) ArenaLists::backgroundFinalize(&fop, arenas, &emptyArenas); } @@ -5443,7 +5487,7 @@ SweepArenaList(ArenaHeader** arenasToSweep, SliceBudget& sliceBudget, Args... ar *arenasToSweep = (*arenasToSweep)->next; AllocKind kind = MapTypeToFinalizeKind::kind; - sliceBudget.step(Arena::thingsPerArena(Arena::thingSize(kind))); + sliceBudget.step(Arena::thingsPerArena(kind)); if (sliceBudget.isOverBudget()) return false; } @@ -5516,7 +5560,7 @@ GCRuntime::sweepPhase(SliceBudget& sliceBudget) AllocKind kind = IncrementalFinalizePhases[finalizePhase].kinds[sweepKindIndex]; /* Set the number of things per arena for this AllocKind. */ - size_t thingsPerArena = Arena::thingsPerArena(Arena::thingSize(kind)); + size_t thingsPerArena = Arena::thingsPerArena(kind); incrementalSweepList.setThingsPerArena(thingsPerArena); if (!zone->arenas.foregroundFinalize(&fop, kind, sliceBudget, diff --git a/js/src/jsgc.h b/js/src/jsgc.h index e19b4ce607ff..eec0b9e1135f 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -306,6 +306,7 @@ struct SortedArenaListSegment void append(ArenaHeader* aheader) { MOZ_ASSERT(aheader); MOZ_ASSERT_IF(head, head->getAllocKind() == aheader->getAllocKind()); + MOZ_RELEASE_ASSERT(uintptr_t(aheader) != uintptr_t(UINT64_C(0x4b4b4b4b4b4b4b4b))); *tailp = aheader; tailp = &aheader->next; } @@ -316,6 +317,7 @@ struct SortedArenaListSegment // description of ArenaList), but from the perspective of a SortedArenaList // this makes no difference. void linkTo(ArenaHeader* aheader) { + MOZ_RELEASE_ASSERT(uintptr_t(aheader) != uintptr_t(UINT64_C(0x4b4b4b4b4b4b4b4b))); *tailp = aheader; } }; @@ -544,6 +546,7 @@ class SortedArenaList void extractEmpty(ArenaHeader** empty) { SortedArenaListSegment& segment = segments[thingsPerArena_]; if (segment.head) { + MOZ_RELEASE_ASSERT(uintptr_t(*empty) != uintptr_t(UINT64_C(0x4b4b4b4b4b4b4b4b))); *segment.tailp = *empty; *empty = segment.head; segment.clear(); diff --git a/js/src/tests/ecma_7/SIMD/shifts.js b/js/src/tests/ecma_7/SIMD/shifts.js index f9e58adbc2d4..7f5e5db99642 100644 --- a/js/src/tests/ecma_7/SIMD/shifts.js +++ b/js/src/tests/ecma_7/SIMD/shifts.js @@ -92,8 +92,6 @@ function test() { for (var bits = -2; bits < 12; bits++) { testBinaryScalarFunc(v, bits, Int8x16.shiftLeftByScalar, lsh8); testBinaryScalarFunc(v, bits, Int8x16.shiftRightByScalar, rsha8); - testBinaryScalarFunc(v, bits, Int8x16.shiftRightArithmeticByScalar, rsha8); - testBinaryScalarFunc(v, bits, Int8x16.shiftRightLogicalByScalar, rshl8); } // Test that the shift count is coerced to an int32. testBinaryScalarFunc(v, undefined, Int8x16.shiftLeftByScalar, lsh8); @@ -108,8 +106,6 @@ function test() { for (var bits = -2; bits < 20; bits++) { testBinaryScalarFunc(v, bits, Int16x8.shiftLeftByScalar, lsh16); testBinaryScalarFunc(v, bits, Int16x8.shiftRightByScalar, rsha16); - testBinaryScalarFunc(v, bits, Int16x8.shiftRightArithmeticByScalar, rsha16); - testBinaryScalarFunc(v, bits, Int16x8.shiftRightLogicalByScalar, rshl16); } // Test that the shift count is coerced to an int32. testBinaryScalarFunc(v, undefined, Int16x8.shiftLeftByScalar, lsh16); @@ -124,8 +120,6 @@ function test() { for (var bits = -2; bits < 36; bits++) { testBinaryScalarFunc(v, bits, Int32x4.shiftLeftByScalar, lsh32); testBinaryScalarFunc(v, bits, Int32x4.shiftRightByScalar, rsha32); - testBinaryScalarFunc(v, bits, Int32x4.shiftRightArithmeticByScalar, rsha32); - testBinaryScalarFunc(v, bits, Int32x4.shiftRightLogicalByScalar, rshl32); } // Test that the shift count is coerced to an int32. testBinaryScalarFunc(v, undefined, Int32x4.shiftLeftByScalar, lsh32); @@ -141,8 +135,6 @@ function test() { for (var bits = -2; bits < 12; bits++) { testBinaryScalarFunc(v, bits, Uint8x16.shiftLeftByScalar, ulsh8); testBinaryScalarFunc(v, bits, Uint8x16.shiftRightByScalar, urshl8); - testBinaryScalarFunc(v, bits, Uint8x16.shiftRightArithmeticByScalar, ursha8); - testBinaryScalarFunc(v, bits, Uint8x16.shiftRightLogicalByScalar, urshl8); } // Test that the shift count is coerced to an int32. testBinaryScalarFunc(v, undefined, Uint8x16.shiftLeftByScalar, ulsh8); @@ -157,8 +149,6 @@ function test() { for (var bits = -2; bits < 20; bits++) { testBinaryScalarFunc(v, bits, Uint16x8.shiftLeftByScalar, ulsh16); testBinaryScalarFunc(v, bits, Uint16x8.shiftRightByScalar, urshl16); - testBinaryScalarFunc(v, bits, Uint16x8.shiftRightArithmeticByScalar, ursha16); - testBinaryScalarFunc(v, bits, Uint16x8.shiftRightLogicalByScalar, urshl16); } // Test that the shift count is coerced to an int32. testBinaryScalarFunc(v, undefined, Uint16x8.shiftLeftByScalar, ulsh16); @@ -174,8 +164,6 @@ function test() { for (var bits = -2; bits < 36; bits++) { testBinaryScalarFunc(v, bits, Uint32x4.shiftLeftByScalar, ulsh32); testBinaryScalarFunc(v, bits, Uint32x4.shiftRightByScalar, urshl32); - testBinaryScalarFunc(v, bits, Uint32x4.shiftRightArithmeticByScalar, ursha32); - testBinaryScalarFunc(v, bits, Uint32x4.shiftRightLogicalByScalar, urshl32); } // Test that the shift count is coerced to an int32. testBinaryScalarFunc(v, undefined, Uint32x4.shiftLeftByScalar, ulsh32); @@ -186,38 +174,26 @@ function test() { var v = SIMD.Int8x16(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16); assertThrowsInstanceOf(() => SIMD.Int8x16.shiftLeftByScalar(v, bad), TestError); assertThrowsInstanceOf(() => SIMD.Int8x16.shiftRightByScalar(v, bad), TestError); - assertThrowsInstanceOf(() => SIMD.Int8x16.shiftRightArithmeticByScalar(v, bad), TestError); - assertThrowsInstanceOf(() => SIMD.Int8x16.shiftRightLogicalByScalar(v, bad), TestError); var v = SIMD.Int16x8(1,2,3,4,5,6,7,8); assertThrowsInstanceOf(() => SIMD.Int16x8.shiftLeftByScalar(v, bad), TestError); assertThrowsInstanceOf(() => SIMD.Int16x8.shiftRightByScalar(v, bad), TestError); - assertThrowsInstanceOf(() => SIMD.Int16x8.shiftRightArithmeticByScalar(v, bad), TestError); - assertThrowsInstanceOf(() => SIMD.Int16x8.shiftRightLogicalByScalar(v, bad), TestError); var v = SIMD.Int32x4(1,2,3,4); assertThrowsInstanceOf(() => SIMD.Int32x4.shiftLeftByScalar(v, bad), TestError); assertThrowsInstanceOf(() => SIMD.Int32x4.shiftRightByScalar(v, bad), TestError); - assertThrowsInstanceOf(() => SIMD.Int32x4.shiftRightArithmeticByScalar(v, bad), TestError); - assertThrowsInstanceOf(() => SIMD.Int32x4.shiftRightLogicalByScalar(v, bad), TestError); var v = SIMD.Uint8x16(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16); assertThrowsInstanceOf(() => SIMD.Uint8x16.shiftLeftByScalar(v, bad), TestError); assertThrowsInstanceOf(() => SIMD.Uint8x16.shiftRightByScalar(v, bad), TestError); - assertThrowsInstanceOf(() => SIMD.Uint8x16.shiftRightArithmeticByScalar(v, bad), TestError); - assertThrowsInstanceOf(() => SIMD.Uint8x16.shiftRightLogicalByScalar(v, bad), TestError); var v = SIMD.Uint16x8(1,2,3,4,5,6,7,8); assertThrowsInstanceOf(() => SIMD.Uint16x8.shiftLeftByScalar(v, bad), TestError); assertThrowsInstanceOf(() => SIMD.Uint16x8.shiftRightByScalar(v, bad), TestError); - assertThrowsInstanceOf(() => SIMD.Uint16x8.shiftRightArithmeticByScalar(v, bad), TestError); - assertThrowsInstanceOf(() => SIMD.Uint16x8.shiftRightLogicalByScalar(v, bad), TestError); var v = SIMD.Uint32x4(1,2,3,4); assertThrowsInstanceOf(() => SIMD.Uint32x4.shiftLeftByScalar(v, bad), TestError); assertThrowsInstanceOf(() => SIMD.Uint32x4.shiftRightByScalar(v, bad), TestError); - assertThrowsInstanceOf(() => SIMD.Uint32x4.shiftRightArithmeticByScalar(v, bad), TestError); - assertThrowsInstanceOf(() => SIMD.Uint32x4.shiftRightLogicalByScalar(v, bad), TestError); if (typeof reportCompare === "function") reportCompare(true, true); diff --git a/js/src/vm/MemoryMetrics.cpp b/js/src/vm/MemoryMetrics.cpp index 6af6f463c730..6be0fde81c14 100644 --- a/js/src/vm/MemoryMetrics.cpp +++ b/js/src/vm/MemoryMetrics.cpp @@ -356,7 +356,7 @@ StatsArenaCallback(JSRuntime* rt, void* data, gc::Arena* arena, // The admin space includes (a) the header and (b) the padding between the // end of the header and the start of the first GC thing. - size_t allocationSpace = arena->thingsSpan(thingSize); + size_t allocationSpace = Arena::thingsSpan(arena->aheader.getAllocKind()); rtStats->currZoneStats->gcHeapArenaAdmin += gc::ArenaSize - allocationSpace; // We don't call the callback on unused things. So we compute the diff --git a/layout/base/ActiveLayerTracker.cpp b/layout/base/ActiveLayerTracker.cpp index cd071b739a6f..6ae671f09611 100644 --- a/layout/base/ActiveLayerTracker.cpp +++ b/layout/base/ActiveLayerTracker.cpp @@ -20,6 +20,7 @@ #include "nsStyleTransformMatrix.h" #include "nsTransitionManager.h" #include "nsDisplayList.h" +#include "nsDOMCSSDeclaration.h" namespace mozilla { @@ -311,12 +312,21 @@ ActiveLayerTracker::NotifyOffsetRestyle(nsIFrame* aFrame) } /* static */ void -ActiveLayerTracker::NotifyAnimated(nsIFrame* aFrame, nsCSSProperty aProperty) +ActiveLayerTracker::NotifyAnimated(nsIFrame* aFrame, + nsCSSProperty aProperty, + const nsAString& aNewValue, + nsDOMCSSDeclaration* aDOMCSSDecl) { LayerActivity* layerActivity = GetLayerActivityForUpdate(aFrame); uint8_t& mutationCount = layerActivity->RestyleCountForProperty(aProperty); - // We know this is animated, so just hack the mutation count. - mutationCount = 0xFF; + if (mutationCount != 0xFF) { + nsAutoString oldValue; + aDOMCSSDecl->GetPropertyValue(aProperty, oldValue); + if (aNewValue != oldValue) { + // We know this is animated, so just hack the mutation count. + mutationCount = 0xFF; + } + } } /* static */ void @@ -354,10 +364,12 @@ IsPresContextInScriptAnimationCallback(nsPresContext* aPresContext) /* static */ void ActiveLayerTracker::NotifyInlineStyleRuleModified(nsIFrame* aFrame, - nsCSSProperty aProperty) + nsCSSProperty aProperty, + const nsAString& aNewValue, + nsDOMCSSDeclaration* aDOMCSSDecl) { if (IsPresContextInScriptAnimationCallback(aFrame->PresContext())) { - NotifyAnimated(aFrame, aProperty); + NotifyAnimated(aFrame, aProperty, aNewValue, aDOMCSSDecl); } if (gLayerActivityTracker && gLayerActivityTracker->mCurrentScrollHandlerFrame.IsAlive()) { diff --git a/layout/base/ActiveLayerTracker.h b/layout/base/ActiveLayerTracker.h index 302b0ba13d20..479fb89a1f0e 100644 --- a/layout/base/ActiveLayerTracker.h +++ b/layout/base/ActiveLayerTracker.h @@ -10,6 +10,7 @@ class nsIFrame; class nsIContent; class nsDisplayListBuilder; +class nsDOMCSSDeclaration; namespace mozilla { @@ -47,8 +48,12 @@ public: /** * Mark aFrame as being known to have an animation of aProperty. * Any such marking will time out after a short period. + * aNewValue and aDOMCSSDecl are used to determine whether the property's + * value has changed. */ - static void NotifyAnimated(nsIFrame* aFrame, nsCSSProperty aProperty); + static void NotifyAnimated(nsIFrame* aFrame, nsCSSProperty aProperty, + const nsAString& aNewValue, + nsDOMCSSDeclaration* aDOMCSSDecl); /** * Notify aFrame as being known to have an animation of aProperty through an * inline style modification during aScrollFrame's scroll event handler. @@ -60,8 +65,12 @@ public: * has been modified. * This notification is incomplete --- not all modifications to inline * style will trigger this. + * aNewValue and aDOMCSSDecl are used to determine whether the property's + * value has changed. */ - static void NotifyInlineStyleRuleModified(nsIFrame* aFrame, nsCSSProperty aProperty); + static void NotifyInlineStyleRuleModified(nsIFrame* aFrame, nsCSSProperty aProperty, + const nsAString& aNewValue, + nsDOMCSSDeclaration* aDOMCSSDecl); /** * Return true if aFrame's aProperty style should be considered as being animated * for pre-rendering. diff --git a/layout/base/RestyleManager.cpp b/layout/base/RestyleManager.cpp index 947048132daa..bbc0109d3194 100644 --- a/layout/base/RestyleManager.cpp +++ b/layout/base/RestyleManager.cpp @@ -21,6 +21,7 @@ #include "nsStyleUtil.h" #include "nsCSSFrameConstructor.h" #include "nsSVGEffects.h" +#include "nsCSSPseudoElements.h" #include "nsCSSRendering.h" #include "nsAnimationManager.h" #include "nsTransitionManager.h" @@ -1104,18 +1105,15 @@ RestyleManager::AnimationsWithDestroyedFrame::AnimationsWithDestroyedFrame( void RestyleManager::AnimationsWithDestroyedFrame::StopAnimationsForElementsWithoutFrames() { - StopAnimationsWithoutFrame(mContents, - nsCSSPseudoElements::ePseudo_NotPseudoElement); - StopAnimationsWithoutFrame(mBeforeContents, - nsCSSPseudoElements::ePseudo_before); - StopAnimationsWithoutFrame(mAfterContents, - nsCSSPseudoElements::ePseudo_after); + StopAnimationsWithoutFrame(mContents, CSSPseudoElementType::NotPseudo); + StopAnimationsWithoutFrame(mBeforeContents, CSSPseudoElementType::before); + StopAnimationsWithoutFrame(mAfterContents, CSSPseudoElementType::after); } void RestyleManager::AnimationsWithDestroyedFrame::StopAnimationsWithoutFrame( nsTArray>& aArray, - nsCSSPseudoElements::Type aPseudoType) + CSSPseudoElementType aPseudoType) { nsAnimationManager* animationManager = mRestyleManager->PresContext()->AnimationManager(); @@ -1132,7 +1130,7 @@ RestyleManager::AnimationsWithDestroyedFrame::StopAnimationsWithoutFrame( static inline dom::Element* ElementForStyleContext(nsIContent* aParentContent, nsIFrame* aFrame, - nsCSSPseudoElements::Type aPseudoType); + CSSPseudoElementType aPseudoType); // Forwarded nsIDocumentObserver method, to handle restyling (and // passing the notification to the frame). @@ -1159,8 +1157,7 @@ RestyleManager::ContentStateChanged(nsIContent* aContent, // need to force a reframe -- if it's needed, the HasStateDependentStyle // call will handle things. nsIFrame* primaryFrame = aElement->GetPrimaryFrame(); - nsCSSPseudoElements::Type pseudoType = - nsCSSPseudoElements::ePseudo_NotPseudoElement; + CSSPseudoElementType pseudoType = CSSPseudoElementType::NotPseudo; if (primaryFrame) { // If it's generated content, ignore LOADING/etc state changes on it. if (!primaryFrame->IsGeneratedContentFrame() && @@ -1192,7 +1189,7 @@ RestyleManager::ContentStateChanged(nsIContent* aContent, nsRestyleHint rshint; - if (pseudoType >= nsCSSPseudoElements::ePseudo_PseudoElementCount) { + if (pseudoType >= CSSPseudoElementType::Count) { rshint = styleSet->HasStateDependentStyle(aElement, aStateMask); } else if (nsCSSPseudoElements::PseudoElementSupportsUserActionState( pseudoType)) { @@ -2129,31 +2126,31 @@ RestyleManager::TryStartingTransition(nsPresContext* aPresContext, static dom::Element* ElementForStyleContext(nsIContent* aParentContent, nsIFrame* aFrame, - nsCSSPseudoElements::Type aPseudoType) + CSSPseudoElementType aPseudoType) { // We don't expect XUL tree stuff here. - NS_PRECONDITION(aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement || - aPseudoType == nsCSSPseudoElements::ePseudo_AnonBox || - aPseudoType < nsCSSPseudoElements::ePseudo_PseudoElementCount, + NS_PRECONDITION(aPseudoType == CSSPseudoElementType::NotPseudo || + aPseudoType == CSSPseudoElementType::AnonBox || + aPseudoType < CSSPseudoElementType::Count, "Unexpected pseudo"); // XXX see the comments about the various element confusion in // ElementRestyler::Restyle. - if (aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) { + if (aPseudoType == CSSPseudoElementType::NotPseudo) { return aFrame->GetContent()->AsElement(); } - if (aPseudoType == nsCSSPseudoElements::ePseudo_AnonBox) { + if (aPseudoType == CSSPseudoElementType::AnonBox) { return nullptr; } - if (aPseudoType == nsCSSPseudoElements::ePseudo_firstLetter) { + if (aPseudoType == CSSPseudoElementType::firstLetter) { NS_ASSERTION(aFrame->GetType() == nsGkAtoms::letterFrame, "firstLetter pseudoTag without a nsFirstLetterFrame"); nsBlockFrame* block = nsBlockFrame::GetNearestAncestorBlock(aFrame); return block->GetContent()->AsElement(); } - if (aPseudoType == nsCSSPseudoElements::ePseudo_mozColorSwatch) { + if (aPseudoType == CSSPseudoElementType::mozColorSwatch) { MOZ_ASSERT(aFrame->GetParent() && aFrame->GetParent()->GetParent(), "Color swatch frame should have a parent & grandparent"); @@ -2165,11 +2162,11 @@ ElementForStyleContext(nsIContent* aParentContent, return grandparentFrame->GetContent()->AsElement(); } - if (aPseudoType == nsCSSPseudoElements::ePseudo_mozNumberText || - aPseudoType == nsCSSPseudoElements::ePseudo_mozNumberWrapper || - aPseudoType == nsCSSPseudoElements::ePseudo_mozNumberSpinBox || - aPseudoType == nsCSSPseudoElements::ePseudo_mozNumberSpinUp || - aPseudoType == nsCSSPseudoElements::ePseudo_mozNumberSpinDown) { + if (aPseudoType == CSSPseudoElementType::mozNumberText || + aPseudoType == CSSPseudoElementType::mozNumberWrapper || + aPseudoType == CSSPseudoElementType::mozNumberSpinBox || + aPseudoType == CSSPseudoElementType::mozNumberSpinUp || + aPseudoType == CSSPseudoElementType::mozNumberSpinDown) { // Get content for nearest nsNumberControlFrame: nsIFrame* f = aFrame->GetParent(); MOZ_ASSERT(f); @@ -2201,9 +2198,9 @@ ElementForStyleContext(nsIContent* aParentContent, */ static dom::Element* PseudoElementForStyleContext(nsIFrame* aFrame, - nsCSSPseudoElements::Type aPseudoType) + CSSPseudoElementType aPseudoType) { - if (aPseudoType >= nsCSSPseudoElements::ePseudo_PseudoElementCount) { + if (aPseudoType >= CSSPseudoElementType::Count) { return nullptr; } @@ -3847,7 +3844,7 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf, #endif nsIAtom* const pseudoTag = oldContext->GetPseudo(); - const nsCSSPseudoElements::Type pseudoType = oldContext->GetPseudoType(); + const CSSPseudoElementType pseudoType = oldContext->GetPseudoType(); // Get the frame providing the parent style context. If it is a // child, then resolve the provider first. @@ -3942,7 +3939,7 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf, parentContext, oldContext, rshint); } - } else if (pseudoType == nsCSSPseudoElements::ePseudo_AnonBox) { + } else if (pseudoType == CSSPseudoElementType::AnonBox) { newContext = styleSet->ResolveAnonymousBoxStyle(pseudoTag, parentContext); } @@ -3976,8 +3973,7 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf, } else { // Don't expect XUL tree stuff here, since it needs a comparator and // all. - NS_ASSERTION(pseudoType < - nsCSSPseudoElements::ePseudo_PseudoElementCount, + NS_ASSERTION(pseudoType < CSSPseudoElementType::Count, "Unexpected pseudo type"); Element* pseudoElement = PseudoElementForStyleContext(aSelf, pseudoType); @@ -4258,12 +4254,12 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf, LOG_RESTYLE_INDENT(); RefPtr newExtraContext; nsIAtom* const extraPseudoTag = oldExtraContext->GetPseudo(); - const nsCSSPseudoElements::Type extraPseudoType = + const CSSPseudoElementType extraPseudoType = oldExtraContext->GetPseudoType(); NS_ASSERTION(extraPseudoTag && extraPseudoTag != nsCSSAnonBoxes::mozNonElement, "extra style context is not pseudo element"); - Element* element = extraPseudoType != nsCSSPseudoElements::ePseudo_AnonBox + Element* element = extraPseudoType != CSSPseudoElementType::AnonBox ? mContent->AsElement() : nullptr; if (!MustRestyleSelf(aRestyleHint, element)) { if (CanReparentStyleContext(aRestyleHint)) { @@ -4285,14 +4281,13 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf, newContext, oldExtraContext, nsRestyleHint(0)); } - } else if (extraPseudoType == nsCSSPseudoElements::ePseudo_AnonBox) { + } else if (extraPseudoType == CSSPseudoElementType::AnonBox) { newExtraContext = styleSet->ResolveAnonymousBoxStyle(extraPseudoTag, newContext); } else { // Don't expect XUL tree stuff here, since it needs a comparator and // all. - NS_ASSERTION(extraPseudoType < - nsCSSPseudoElements::ePseudo_PseudoElementCount, + NS_ASSERTION(extraPseudoType < CSSPseudoElementType::Count, "Unexpected type"); newExtraContext = styleSet->ResolvePseudoElementStyle(mContent->AsElement(), extraPseudoType, @@ -4401,11 +4396,11 @@ ElementRestyler::RestyleChildrenOfDisplayContentsElement( const bool mightReframePseudos = aRestyleHint & eRestyle_Subtree; DoRestyleUndisplayedDescendants(nsRestyleHint(0), mContent, aNewContext); if (!(mHintsHandled & nsChangeHint_ReconstructFrame) && mightReframePseudos) { - MaybeReframeForPseudo(nsCSSPseudoElements::ePseudo_before, + MaybeReframeForPseudo(CSSPseudoElementType::before, aParentFrame, nullptr, mContent, aNewContext); } if (!(mHintsHandled & nsChangeHint_ReconstructFrame) && mightReframePseudos) { - MaybeReframeForPseudo(nsCSSPseudoElements::ePseudo_after, + MaybeReframeForPseudo(CSSPseudoElementType::after, aParentFrame, nullptr, mContent, aNewContext); } if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) { @@ -4646,7 +4641,7 @@ ElementRestyler::RestyleUndisplayedNodes(nsRestyleHint aChildRestyleHint, void ElementRestyler::MaybeReframeForBeforePseudo() { - MaybeReframeForPseudo(nsCSSPseudoElements::ePseudo_before, + MaybeReframeForPseudo(CSSPseudoElementType::before, mFrame, mFrame, mFrame->GetContent(), mFrame->StyleContext()); } @@ -4659,7 +4654,7 @@ void ElementRestyler::MaybeReframeForAfterPseudo(nsIFrame* aFrame) { MOZ_ASSERT(aFrame); - MaybeReframeForPseudo(nsCSSPseudoElements::ePseudo_after, + MaybeReframeForPseudo(CSSPseudoElementType::after, aFrame, aFrame, aFrame->GetContent(), aFrame->StyleContext()); } @@ -4668,7 +4663,7 @@ ElementRestyler::MaybeReframeForAfterPseudo(nsIFrame* aFrame) bool ElementRestyler::MustReframeForBeforePseudo() { - return MustReframeForPseudo(nsCSSPseudoElements::ePseudo_before, + return MustReframeForPseudo(CSSPseudoElementType::before, mFrame, mFrame, mFrame->GetContent(), mFrame->StyleContext()); } @@ -4677,14 +4672,14 @@ bool ElementRestyler::MustReframeForAfterPseudo(nsIFrame* aFrame) { MOZ_ASSERT(aFrame); - return MustReframeForPseudo(nsCSSPseudoElements::ePseudo_after, + return MustReframeForPseudo(CSSPseudoElementType::after, aFrame, aFrame, aFrame->GetContent(), aFrame->StyleContext()); } #endif void -ElementRestyler::MaybeReframeForPseudo(nsCSSPseudoElements::Type aPseudoType, +ElementRestyler::MaybeReframeForPseudo(CSSPseudoElementType aPseudoType, nsIFrame* aGenConParentFrame, nsIFrame* aFrame, nsIContent* aContent, @@ -4701,14 +4696,14 @@ ElementRestyler::MaybeReframeForPseudo(nsCSSPseudoElements::Type aPseudoType, } bool -ElementRestyler::MustReframeForPseudo(nsCSSPseudoElements::Type aPseudoType, +ElementRestyler::MustReframeForPseudo(CSSPseudoElementType aPseudoType, nsIFrame* aGenConParentFrame, nsIFrame* aFrame, nsIContent* aContent, nsStyleContext* aStyleContext) { - MOZ_ASSERT(aPseudoType == nsCSSPseudoElements::ePseudo_before || - aPseudoType == nsCSSPseudoElements::ePseudo_after); + MOZ_ASSERT(aPseudoType == CSSPseudoElementType::before || + aPseudoType == CSSPseudoElementType::after); // Make sure not to do this for pseudo-frames... if (aStyleContext->GetPseudo()) { @@ -4724,7 +4719,7 @@ ElementRestyler::MustReframeForPseudo(nsCSSPseudoElements::Type aPseudoType, } } - if (aPseudoType == nsCSSPseudoElements::ePseudo_before) { + if (aPseudoType == CSSPseudoElementType::before) { // Check for a ::before pseudo style and the absence of a ::before content, // but only if aFrame is null or is the first continuation/ib-split. if ((aFrame && !nsLayoutUtils::IsFirstContinuationOrIBSplitSibling(aFrame)) || diff --git a/layout/base/RestyleManager.h b/layout/base/RestyleManager.h index 7bb8cb7ab8c2..de4f1757dcb6 100644 --- a/layout/base/RestyleManager.h +++ b/layout/base/RestyleManager.h @@ -18,7 +18,6 @@ #include "nsPresContext.h" #include "nsRefreshDriver.h" #include "nsRefPtrHashtable.h" -#include "nsCSSPseudoElements.h" #include "nsTransitionManager.h" class nsIFrame; @@ -26,6 +25,7 @@ class nsStyleChangeList; struct TreeMatchContext; namespace mozilla { + enum class CSSPseudoElementType : uint8_t; class EventStates; struct UndisplayedNode; @@ -191,29 +191,29 @@ public: void Put(nsIContent* aContent, nsStyleContext* aStyleContext) { MOZ_ASSERT(aContent); - nsCSSPseudoElements::Type pseudoType = aStyleContext->GetPseudoType(); - if (pseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) { + CSSPseudoElementType pseudoType = aStyleContext->GetPseudoType(); + if (pseudoType == CSSPseudoElementType::NotPseudo) { mElementContexts.Put(aContent, aStyleContext); - } else if (pseudoType == nsCSSPseudoElements::ePseudo_before) { + } else if (pseudoType == CSSPseudoElementType::before) { MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentbefore); mBeforePseudoContexts.Put(aContent->GetParent(), aStyleContext); - } else if (pseudoType == nsCSSPseudoElements::ePseudo_after) { + } else if (pseudoType == CSSPseudoElementType::after) { MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentafter); mAfterPseudoContexts.Put(aContent->GetParent(), aStyleContext); } } nsStyleContext* Get(nsIContent* aContent, - nsCSSPseudoElements::Type aPseudoType) { + CSSPseudoElementType aPseudoType) { MOZ_ASSERT(aContent); - if (aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) { + if (aPseudoType == CSSPseudoElementType::NotPseudo) { return mElementContexts.GetWeak(aContent); } - if (aPseudoType == nsCSSPseudoElements::ePseudo_before) { + if (aPseudoType == CSSPseudoElementType::before) { MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentbefore); return mBeforePseudoContexts.GetWeak(aContent->GetParent()); } - if (aPseudoType == nsCSSPseudoElements::ePseudo_after) { + if (aPseudoType == CSSPseudoElementType::after) { MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentafter); return mAfterPseudoContexts.GetWeak(aContent->GetParent()); } @@ -269,13 +269,13 @@ public: // the real element. void Put(nsIContent* aContent, nsStyleContext* aStyleContext) { MOZ_ASSERT(aContent); - nsCSSPseudoElements::Type pseudoType = aStyleContext->GetPseudoType(); - if (pseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) { + CSSPseudoElementType pseudoType = aStyleContext->GetPseudoType(); + if (pseudoType == CSSPseudoElementType::NotPseudo) { mContents.AppendElement(aContent); - } else if (pseudoType == nsCSSPseudoElements::ePseudo_before) { + } else if (pseudoType == CSSPseudoElementType::before) { MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentbefore); mBeforeContents.AppendElement(aContent->GetParent()); - } else if (pseudoType == nsCSSPseudoElements::ePseudo_after) { + } else if (pseudoType == CSSPseudoElementType::after) { MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentafter); mAfterContents.AppendElement(aContent->GetParent()); } @@ -285,7 +285,7 @@ public: private: void StopAnimationsWithoutFrame(nsTArray>& aArray, - nsCSSPseudoElements::Type aPseudoType); + CSSPseudoElementType aPseudoType); RestyleManager* mRestyleManager; AutoRestore mRestorePointer; @@ -792,7 +792,7 @@ private: const uint8_t aDisplay); void MaybeReframeForBeforePseudo(); void MaybeReframeForAfterPseudo(nsIFrame* aFrame); - void MaybeReframeForPseudo(nsCSSPseudoElements::Type aPseudoType, + void MaybeReframeForPseudo(CSSPseudoElementType aPseudoType, nsIFrame* aGenConParentFrame, nsIFrame* aFrame, nsIContent* aContent, @@ -801,7 +801,7 @@ private: bool MustReframeForBeforePseudo(); bool MustReframeForAfterPseudo(nsIFrame* aFrame); #endif - bool MustReframeForPseudo(nsCSSPseudoElements::Type aPseudoType, + bool MustReframeForPseudo(CSSPseudoElementType aPseudoType, nsIFrame* aGenConParentFrame, nsIFrame* aFrame, nsIContent* aContent, diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 17778401eade..ed687745dd9b 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -20,6 +20,7 @@ #include "mozilla/Likely.h" #include "mozilla/LinkedList.h" #include "nsAbsoluteContainingBlock.h" +#include "nsCSSPseudoElements.h" #include "nsIAtom.h" #include "nsIFrameInlines.h" #include "nsGkAtoms.h" @@ -1757,11 +1758,11 @@ nsCSSFrameConstructor::CreateGeneratedContentItem(nsFrameConstructorState& aStat nsContainerFrame* aParentFrame, nsIContent* aParentContent, nsStyleContext* aStyleContext, - nsCSSPseudoElements::Type aPseudoElement, + CSSPseudoElementType aPseudoElement, FrameConstructionItemList& aItems) { - MOZ_ASSERT(aPseudoElement == nsCSSPseudoElements::ePseudo_before || - aPseudoElement == nsCSSPseudoElements::ePseudo_after, + MOZ_ASSERT(aPseudoElement == CSSPseudoElementType::before || + aPseudoElement == CSSPseudoElementType::after, "unexpected aPseudoElement"); // XXXbz is this ever true? @@ -1782,7 +1783,7 @@ nsCSSFrameConstructor::CreateGeneratedContentItem(nsFrameConstructorState& aStat if (!pseudoStyleContext) return; - bool isBefore = aPseudoElement == nsCSSPseudoElements::ePseudo_before; + bool isBefore = aPseudoElement == CSSPseudoElementType::before; // |ProbePseudoStyleFor| checked the 'display' property and the // |ContentCount()| of the 'content' property for us. @@ -2961,7 +2962,7 @@ nsCSSFrameConstructor::CreateBackdropFrameFor(nsIPresShell* aPresShell, RefPtr style = aPresShell->StyleSet()-> ResolvePseudoElementStyle(aContent->AsElement(), - nsCSSPseudoElements::ePseudo_backdrop, + CSSPseudoElementType::backdrop, /* aParentStyleContext */ nullptr, /* aPseudoElement */ nullptr); nsBackdropFrame* backdropFrame = new (aPresShell) nsBackdropFrame(style); @@ -4922,7 +4923,7 @@ nsCSSFrameConstructor::ResolveStyleContext(nsStyleContext* aParentStyleContext, RestyleManager()->GetReframingStyleContexts(); if (rsc) { nsStyleContext* oldStyleContext = - rsc->Get(aContent, nsCSSPseudoElements::ePseudo_NotPseudoElement); + rsc->Get(aContent, CSSPseudoElementType::NotPseudo); nsPresContext* presContext = mPresShell->GetPresContext(); if (oldStyleContext) { RestyleManager::TryStartingTransition(presContext, aContent, @@ -4930,7 +4931,7 @@ nsCSSFrameConstructor::ResolveStyleContext(nsStyleContext* aParentStyleContext, } else if (aContent->IsElement()) { presContext->TransitionManager()-> PruneCompletedTransitions(aContent->AsElement(), - nsCSSPseudoElements::ePseudo_NotPseudoElement, result); + CSSPseudoElementType::NotPseudo, result); } } @@ -5763,7 +5764,7 @@ nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState aParentFrame->AddStateBits(NS_FRAME_MAY_HAVE_GENERATED_CONTENT); } CreateGeneratedContentItem(aState, aParentFrame, aContent, styleContext, - nsCSSPseudoElements::ePseudo_before, aItems); + CSSPseudoElementType::before, aItems); FlattenedChildIterator iter(aContent); for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) { @@ -5796,7 +5797,7 @@ nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState aItems.SetParentHasNoXBLChildren(!iter.XBLInvolved()); CreateGeneratedContentItem(aState, aParentFrame, aContent, styleContext, - nsCSSPseudoElements::ePseudo_after, aItems); + CSSPseudoElementType::after, aItems); if (canHavePageBreak && display->mBreakAfter) { AddPageBreakItem(aContent, aStyleContext, aItems); } @@ -6170,7 +6171,7 @@ AdjustAppendParentForAfterContent(nsFrameManager* aFrameManager, // document than aChild and return that in aAfterFrame. if (aParentFrame->GetGenConPseudos() || nsLayoutUtils::HasPseudoStyle(aContainer, aParentFrame->StyleContext(), - nsCSSPseudoElements::ePseudo_after, + CSSPseudoElementType::after, aParentFrame->PresContext()) || aFrameManager->GetDisplayContentsStyleFor(aContainer)) { nsIFrame* afterFrame = nullptr; @@ -9556,7 +9557,7 @@ nsCSSFrameConstructor::GetFirstLetterStyle(nsIContent* aContent, if (aContent) { return mPresShell->StyleSet()-> ResolvePseudoElementStyle(aContent->AsElement(), - nsCSSPseudoElements::ePseudo_firstLetter, + CSSPseudoElementType::firstLetter, aStyleContext, nullptr); } @@ -9570,7 +9571,7 @@ nsCSSFrameConstructor::GetFirstLineStyle(nsIContent* aContent, if (aContent) { return mPresShell->StyleSet()-> ResolvePseudoElementStyle(aContent->AsElement(), - nsCSSPseudoElements::ePseudo_firstLine, + CSSPseudoElementType::firstLine, aStyleContext, nullptr); } @@ -9584,7 +9585,7 @@ nsCSSFrameConstructor::ShouldHaveFirstLetterStyle(nsIContent* aContent, nsStyleContext* aStyleContext) { return nsLayoutUtils::HasPseudoStyle(aContent, aStyleContext, - nsCSSPseudoElements::ePseudo_firstLetter, + CSSPseudoElementType::firstLetter, mPresShell->GetPresContext()); } @@ -9604,7 +9605,7 @@ nsCSSFrameConstructor::ShouldHaveFirstLineStyle(nsIContent* aContent, { bool hasFirstLine = nsLayoutUtils::HasPseudoStyle(aContent, aStyleContext, - nsCSSPseudoElements::ePseudo_firstLine, + CSSPseudoElementType::firstLine, mPresShell->GetPresContext()); if (hasFirstLine) { // But disable for fieldsets @@ -10532,7 +10533,7 @@ nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState, nsFrame::CorrectStyleParentFrame(aFrame, nullptr)->StyleContext(); // Probe for generated content before CreateGeneratedContentItem(aState, aFrame, aContent, styleContext, - nsCSSPseudoElements::ePseudo_before, + CSSPseudoElementType::before, itemsToConstruct); } @@ -10580,7 +10581,7 @@ nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState, if (aCanHaveGeneratedContent) { // Probe for generated content after CreateGeneratedContentItem(aState, aFrame, aContent, styleContext, - nsCSSPseudoElements::ePseudo_after, + CSSPseudoElementType::after, itemsToConstruct); } } else { @@ -11830,7 +11831,7 @@ nsCSSFrameConstructor::BuildInlineChildItems(nsFrameConstructorState& aState, if (!aItemIsWithinSVGText) { // Probe for generated content before CreateGeneratedContentItem(aState, nullptr, parentContent, parentStyleContext, - nsCSSPseudoElements::ePseudo_before, + CSSPseudoElementType::before, aParentItem.mChildItems); } @@ -11900,7 +11901,7 @@ nsCSSFrameConstructor::BuildInlineChildItems(nsFrameConstructorState& aState, if (!aItemIsWithinSVGText) { // Probe for generated content after CreateGeneratedContentItem(aState, nullptr, parentContent, parentStyleContext, - nsCSSPseudoElements::ePseudo_after, + CSSPseudoElementType::after, aParentItem.mChildItems); } diff --git a/layout/base/nsCSSFrameConstructor.h b/layout/base/nsCSSFrameConstructor.h index 9c5613fd825d..db359312d75b 100644 --- a/layout/base/nsCSSFrameConstructor.h +++ b/layout/base/nsCSSFrameConstructor.h @@ -17,7 +17,6 @@ #include "nsILayoutHistoryState.h" #include "nsQuoteList.h" #include "nsCounterManager.h" -#include "nsCSSPseudoElements.h" #include "nsIAnonymousContentCreator.h" #include "nsFrameManager.h" #include "nsIDocument.h" @@ -51,6 +50,7 @@ class FlattenedChildIterator; class nsCSSFrameConstructor : public nsFrameManager { public: + typedef mozilla::CSSPseudoElementType CSSPseudoElementType; typedef mozilla::dom::Element Element; friend class mozilla::RestyleManager; @@ -452,7 +452,7 @@ private: nsContainerFrame* aFrame, nsIContent* aContent, nsStyleContext* aStyleContext, - nsCSSPseudoElements::Type aPseudoElement, + CSSPseudoElementType aPseudoElement, FrameConstructionItemList& aItems); // This method can change aFrameList: it can chop off the beginning and put diff --git a/layout/base/nsCSSRendering.cpp b/layout/base/nsCSSRendering.cpp index 027c0175e9fd..c6cd21d0d7d6 100644 --- a/layout/base/nsCSSRendering.cpp +++ b/layout/base/nsCSSRendering.cpp @@ -857,7 +857,7 @@ nsCSSRendering::PaintOutline(nsPresContext* aPresContext, nsRect innerRect; if ( #ifdef MOZ_XUL - aStyleContext->GetPseudoType() == nsCSSPseudoElements::ePseudo_XULTree + aStyleContext->GetPseudoType() == CSSPseudoElementType::XULTree #else false #endif diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 34b9da69a2c8..7c8b033e1b98 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -6428,6 +6428,7 @@ nsDisplayVR::BuildLayer(nsDisplayListBuilder* aBuilder, newContainerParameters, nullptr, flags); container->SetVRDeviceID(mHMD->GetDeviceInfo().GetDeviceID()); + container->SetInputFrameID(mHMD->GetSensorState().inputFrameID); container->SetUserData(nsIFrame::LayerIsPrerenderedDataKey(), /*the value is irrelevant*/nullptr); diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 2043b053a981..a9fd068a7fee 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -2035,7 +2035,7 @@ nsLayoutUtils::GetScrolledRect(nsIFrame* aScrolledFrame, bool nsLayoutUtils::HasPseudoStyle(nsIContent* aContent, nsStyleContext* aStyleContext, - nsCSSPseudoElements::Type aPseudoElement, + CSSPseudoElementType aPseudoElement, nsPresContext* aPresContext) { NS_PRECONDITION(aPresContext, "Must have a prescontext"); diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index b4dfc8a16adc..5723d9b5f09b 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -16,7 +16,6 @@ #include "mozilla/layout/FrameChildList.h" #include "nsThreadUtils.h" #include "nsIPrincipal.h" -#include "nsCSSPseudoElements.h" #include "FrameMetrics.h" #include "nsIWidget.h" #include "nsCSSProperty.h" @@ -63,6 +62,7 @@ struct nsStyleImageOrientation; struct nsOverflowAreas; namespace mozilla { +enum class CSSPseudoElementType : uint8_t; class EventListenerManager; class SVGImageContext; struct IntrinsicSize; @@ -661,7 +661,7 @@ public: */ static bool HasPseudoStyle(nsIContent* aContent, nsStyleContext* aStyleContext, - nsCSSPseudoElements::Type aPseudoElement, + mozilla::CSSPseudoElementType aPseudoElement, nsPresContext* aPresContext); /** @@ -2199,7 +2199,8 @@ public: */ static bool GetAnimationContent(const nsIFrame* aFrame, nsIContent* &aContentResult, - nsCSSPseudoElements::Type &aPseudoTypeResult); + mozilla::CSSPseudoElementType + &aPseudoTypeResult); /** * Returns true if the frame has current (i.e. running or scheduled-to-run) diff --git a/layout/forms/nsButtonFrameRenderer.cpp b/layout/forms/nsButtonFrameRenderer.cpp index 376c8fed2d94..0254f4b05cba 100644 --- a/layout/forms/nsButtonFrameRenderer.cpp +++ b/layout/forms/nsButtonFrameRenderer.cpp @@ -465,13 +465,13 @@ nsButtonFrameRenderer::ReResolveStyles(nsPresContext* aPresContext) // style for the inner such as a dotted line (Windows) mInnerFocusStyle = styleSet->ProbePseudoElementStyle(mFrame->GetContent()->AsElement(), - nsCSSPseudoElements::ePseudo_mozFocusInner, + CSSPseudoElementType::mozFocusInner, context); // style for outer focus like a ridged border (MAC). mOuterFocusStyle = styleSet->ProbePseudoElementStyle(mFrame->GetContent()->AsElement(), - nsCSSPseudoElements::ePseudo_mozFocusOuter, + CSSPseudoElementType::mozFocusOuter, context); #ifdef DEBUG diff --git a/layout/forms/nsColorControlFrame.cpp b/layout/forms/nsColorControlFrame.cpp index f2c6aa168375..4621c14dc9a7 100644 --- a/layout/forms/nsColorControlFrame.cpp +++ b/layout/forms/nsColorControlFrame.cpp @@ -8,6 +8,7 @@ #include "nsContentCreatorFunctions.h" #include "nsContentList.h" #include "nsContentUtils.h" +#include "nsCSSPseudoElements.h" #include "nsFormControlFrame.h" #include "nsGkAtoms.h" #include "nsIDOMHTMLInputElement.h" @@ -72,7 +73,7 @@ nsColorControlFrame::CreateAnonymousContent(nsTArray& aElements) nsresult rv = UpdateColor(); NS_ENSURE_SUCCESS(rv, rv); - nsCSSPseudoElements::Type pseudoType = nsCSSPseudoElements::ePseudo_mozColorSwatch; + CSSPseudoElementType pseudoType = CSSPseudoElementType::mozColorSwatch; RefPtr newStyleContext = PresContext()->StyleSet()-> ResolvePseudoElementStyle(mContent->AsElement(), pseudoType, StyleContext(), mColorContent->AsElement()); @@ -135,9 +136,9 @@ nsColorControlFrame::GetContentInsertionFrame() } Element* -nsColorControlFrame::GetPseudoElement(nsCSSPseudoElements::Type aType) +nsColorControlFrame::GetPseudoElement(CSSPseudoElementType aType) { - if (aType == nsCSSPseudoElements::ePseudo_mozColorSwatch) { + if (aType == CSSPseudoElementType::mozColorSwatch) { return mColorContent; } diff --git a/layout/forms/nsColorControlFrame.h b/layout/forms/nsColorControlFrame.h index 584491e56c66..568485c033d7 100644 --- a/layout/forms/nsColorControlFrame.h +++ b/layout/forms/nsColorControlFrame.h @@ -10,6 +10,10 @@ #include "nsHTMLButtonControlFrame.h" #include "nsIAnonymousContentCreator.h" +namespace mozilla { +enum class CSSPseudoElementType : uint8_t; +} // namespace mozilla + typedef nsHTMLButtonControlFrame nsColorControlFrameSuper; // Class which implements the input type=color @@ -17,6 +21,7 @@ typedef nsHTMLButtonControlFrame nsColorControlFrameSuper; class nsColorControlFrame final : public nsColorControlFrameSuper, public nsIAnonymousContentCreator { + typedef mozilla::CSSPseudoElementType CSSPseudoElementType; typedef mozilla::dom::Element Element; public: @@ -47,7 +52,7 @@ public: virtual bool IsLeaf() const override { return true; } virtual nsContainerFrame* GetContentInsertionFrame() override; - virtual Element* GetPseudoElement(nsCSSPseudoElements::Type aType) override; + virtual Element* GetPseudoElement(CSSPseudoElementType aType) override; // Refresh the color swatch, using associated input's value nsresult UpdateColor(); diff --git a/layout/forms/nsMeterFrame.cpp b/layout/forms/nsMeterFrame.cpp index d2797278b59e..a6cf69141b97 100644 --- a/layout/forms/nsMeterFrame.cpp +++ b/layout/forms/nsMeterFrame.cpp @@ -19,6 +19,7 @@ #include "mozilla/dom/Element.h" #include "mozilla/dom/HTMLMeterElement.h" #include "nsContentList.h" +#include "nsCSSPseudoElements.h" #include "nsStyleSet.h" #include "nsThemeConstants.h" #include @@ -66,7 +67,7 @@ nsMeterFrame::CreateAnonymousContent(nsTArray& aElements) mBarDiv = doc->CreateHTMLElement(nsGkAtoms::div); // Associate ::-moz-meter-bar pseudo-element to the anonymous child. - nsCSSPseudoElements::Type pseudoType = nsCSSPseudoElements::ePseudo_mozMeterBar; + CSSPseudoElementType pseudoType = CSSPseudoElementType::mozMeterBar; RefPtr newStyleContext = PresContext()->StyleSet()-> ResolvePseudoElementStyle(mContent->AsElement(), pseudoType, StyleContext(), mBarDiv->AsElement()); @@ -281,9 +282,9 @@ nsMeterFrame::ShouldUseNativeStyle() const } Element* -nsMeterFrame::GetPseudoElement(nsCSSPseudoElements::Type aType) +nsMeterFrame::GetPseudoElement(CSSPseudoElementType aType) { - if (aType == nsCSSPseudoElements::ePseudo_mozMeterBar) { + if (aType == CSSPseudoElementType::mozMeterBar) { return mBarDiv; } diff --git a/layout/forms/nsMeterFrame.h b/layout/forms/nsMeterFrame.h index d7cc32470530..fc6e72cb6f74 100644 --- a/layout/forms/nsMeterFrame.h +++ b/layout/forms/nsMeterFrame.h @@ -73,7 +73,7 @@ public: */ bool ShouldUseNativeStyle() const; - virtual Element* GetPseudoElement(nsCSSPseudoElements::Type aType) override; + virtual Element* GetPseudoElement(CSSPseudoElementType aType) override; protected: // Helper function which reflow the anonymous div frame. diff --git a/layout/forms/nsNumberControlFrame.cpp b/layout/forms/nsNumberControlFrame.cpp index 349afba3a61a..7e3813be0075 100644 --- a/layout/forms/nsNumberControlFrame.cpp +++ b/layout/forms/nsNumberControlFrame.cpp @@ -20,6 +20,7 @@ #include "nsContentUtils.h" #include "nsContentCreatorFunctions.h" #include "nsContentList.h" +#include "nsCSSPseudoElements.h" #include "nsStyleSet.h" #include "nsIDOMMutationEvent.h" #include "nsThreadUtils.h" @@ -323,7 +324,7 @@ nsresult nsNumberControlFrame::MakeAnonymousElement(Element** aResult, nsTArray& aElements, nsIAtom* aTagName, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, nsStyleContext* aParentContext) { // Get the NodeInfoManager and tag necessary to create the anonymous divs. @@ -334,7 +335,7 @@ nsNumberControlFrame::MakeAnonymousElement(Element** aResult, // non-pseudo-element anonymous children, then we'll need to add a branch // that calls ResolveStyleFor((*aResult)->AsElement(), aParentContext)") to // set newStyleContext. - NS_ASSERTION(aPseudoType != nsCSSPseudoElements::ePseudo_NotPseudoElement, + NS_ASSERTION(aPseudoType != CSSPseudoElementType::NotPseudo, "Expecting anonymous children to all be pseudo-elements"); // Associate the pseudo-element with the anonymous child RefPtr newStyleContext = @@ -347,8 +348,8 @@ nsNumberControlFrame::MakeAnonymousElement(Element** aResult, return NS_ERROR_OUT_OF_MEMORY; } - if (aPseudoType == nsCSSPseudoElements::ePseudo_mozNumberSpinDown || - aPseudoType == nsCSSPseudoElements::ePseudo_mozNumberSpinUp) { + if (aPseudoType == CSSPseudoElementType::mozNumberSpinDown || + aPseudoType == CSSPseudoElementType::mozNumberSpinUp) { resultElement->SetAttr(kNameSpaceID_None, nsGkAtoms::role, NS_LITERAL_STRING("button"), false); } @@ -380,7 +381,7 @@ nsNumberControlFrame::CreateAnonymousContent(nsTArray& aElements) rv = MakeAnonymousElement(getter_AddRefs(mOuterWrapper), aElements, nsGkAtoms::div, - nsCSSPseudoElements::ePseudo_mozNumberWrapper, + CSSPseudoElementType::mozNumberWrapper, mStyleContext); NS_ENSURE_SUCCESS(rv, rv); @@ -390,7 +391,7 @@ nsNumberControlFrame::CreateAnonymousContent(nsTArray& aElements) rv = MakeAnonymousElement(getter_AddRefs(mTextField), outerWrapperCI.mChildren, nsGkAtoms::input, - nsCSSPseudoElements::ePseudo_mozNumberText, + CSSPseudoElementType::mozNumberText, outerWrapperCI.mStyleContext); NS_ENSURE_SUCCESS(rv, rv); @@ -438,7 +439,7 @@ nsNumberControlFrame::CreateAnonymousContent(nsTArray& aElements) rv = MakeAnonymousElement(getter_AddRefs(mSpinBox), outerWrapperCI.mChildren, nsGkAtoms::div, - nsCSSPseudoElements::ePseudo_mozNumberSpinBox, + CSSPseudoElementType::mozNumberSpinBox, outerWrapperCI.mStyleContext); NS_ENSURE_SUCCESS(rv, rv); @@ -448,7 +449,7 @@ nsNumberControlFrame::CreateAnonymousContent(nsTArray& aElements) rv = MakeAnonymousElement(getter_AddRefs(mSpinUp), spinBoxCI.mChildren, nsGkAtoms::div, - nsCSSPseudoElements::ePseudo_mozNumberSpinUp, + CSSPseudoElementType::mozNumberSpinUp, spinBoxCI.mStyleContext); NS_ENSURE_SUCCESS(rv, rv); @@ -456,7 +457,7 @@ nsNumberControlFrame::CreateAnonymousContent(nsTArray& aElements) rv = MakeAnonymousElement(getter_AddRefs(mSpinDown), spinBoxCI.mChildren, nsGkAtoms::div, - nsCSSPseudoElements::ePseudo_mozNumberSpinDown, + CSSPseudoElementType::mozNumberSpinDown, spinBoxCI.mStyleContext); SyncDisabledState(); @@ -824,27 +825,27 @@ nsNumberControlFrame::AnonTextControlIsEmpty() } Element* -nsNumberControlFrame::GetPseudoElement(nsCSSPseudoElements::Type aType) +nsNumberControlFrame::GetPseudoElement(CSSPseudoElementType aType) { - if (aType == nsCSSPseudoElements::ePseudo_mozNumberWrapper) { + if (aType == CSSPseudoElementType::mozNumberWrapper) { return mOuterWrapper; } - if (aType == nsCSSPseudoElements::ePseudo_mozNumberText) { + if (aType == CSSPseudoElementType::mozNumberText) { return mTextField; } - if (aType == nsCSSPseudoElements::ePseudo_mozNumberSpinBox) { + if (aType == CSSPseudoElementType::mozNumberSpinBox) { // Might be null. return mSpinBox; } - if (aType == nsCSSPseudoElements::ePseudo_mozNumberSpinUp) { + if (aType == CSSPseudoElementType::mozNumberSpinUp) { // Might be null. return mSpinUp; } - if (aType == nsCSSPseudoElements::ePseudo_mozNumberSpinDown) { + if (aType == CSSPseudoElementType::mozNumberSpinDown) { // Might be null. return mSpinDown; } diff --git a/layout/forms/nsNumberControlFrame.h b/layout/forms/nsNumberControlFrame.h index 458e0abe4b63..1cec12dcd0d9 100644 --- a/layout/forms/nsNumberControlFrame.h +++ b/layout/forms/nsNumberControlFrame.h @@ -16,6 +16,7 @@ class nsPresContext; namespace mozilla { +enum class CSSPseudoElementType : uint8_t; class WidgetEvent; class WidgetGUIEvent; namespace dom { @@ -33,6 +34,7 @@ class nsNumberControlFrame final : public nsContainerFrame friend nsIFrame* NS_NewNumberControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); + typedef mozilla::CSSPseudoElementType CSSPseudoElementType; typedef mozilla::dom::Element Element; typedef mozilla::dom::HTMLInputElement HTMLInputElement; typedef mozilla::WidgetEvent WidgetEvent; @@ -186,7 +188,7 @@ public: */ nsresult HandleSelectCall(); - virtual Element* GetPseudoElement(nsCSSPseudoElements::Type aType) override; + virtual Element* GetPseudoElement(CSSPseudoElementType aType) override; bool ShouldUseNativeStyleForSpinner() const; @@ -196,7 +198,7 @@ private: nsresult MakeAnonymousElement(Element** aResult, nsTArray& aElements, nsIAtom* aTagName, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, nsStyleContext* aParentContext); class SyncDisabledStateEvent; diff --git a/layout/forms/nsProgressFrame.cpp b/layout/forms/nsProgressFrame.cpp index d093bc26abc6..4c6c80b3becc 100644 --- a/layout/forms/nsProgressFrame.cpp +++ b/layout/forms/nsProgressFrame.cpp @@ -19,6 +19,7 @@ #include "mozilla/dom/Element.h" #include "mozilla/dom/HTMLProgressElement.h" #include "nsContentList.h" +#include "nsCSSPseudoElements.h" #include "nsStyleSet.h" #include "nsThemeConstants.h" #include @@ -63,7 +64,7 @@ nsProgressFrame::CreateAnonymousContent(nsTArray& aElements) mBarDiv = doc->CreateHTMLElement(nsGkAtoms::div); // Associate ::-moz-progress-bar pseudo-element to the anonymous child. - nsCSSPseudoElements::Type pseudoType = nsCSSPseudoElements::ePseudo_mozProgressBar; + CSSPseudoElementType pseudoType = CSSPseudoElementType::mozProgressBar; RefPtr newStyleContext = PresContext()->StyleSet()-> ResolvePseudoElementStyle(mContent->AsElement(), pseudoType, StyleContext(), mBarDiv->AsElement()); @@ -287,9 +288,9 @@ nsProgressFrame::ShouldUseNativeStyle() const } Element* -nsProgressFrame::GetPseudoElement(nsCSSPseudoElements::Type aType) +nsProgressFrame::GetPseudoElement(CSSPseudoElementType aType) { - if (aType == nsCSSPseudoElements::ePseudo_mozProgressBar) { + if (aType == CSSPseudoElementType::mozProgressBar) { return mBarDiv; } diff --git a/layout/forms/nsProgressFrame.h b/layout/forms/nsProgressFrame.h index 980e8ba9e2d8..0cecbd25ca8e 100644 --- a/layout/forms/nsProgressFrame.h +++ b/layout/forms/nsProgressFrame.h @@ -11,9 +11,14 @@ #include "nsIAnonymousContentCreator.h" #include "nsCOMPtr.h" +namespace mozilla { +enum class CSSPseudoElementType : uint8_t; +} // namespace mozilla + class nsProgressFrame : public nsContainerFrame, public nsIAnonymousContentCreator { + typedef mozilla::CSSPseudoElementType CSSPseudoElementType; typedef mozilla::dom::Element Element; public: @@ -76,7 +81,7 @@ public: */ bool ShouldUseNativeStyle() const; - virtual Element* GetPseudoElement(nsCSSPseudoElements::Type aType) override; + virtual Element* GetPseudoElement(CSSPseudoElementType aType) override; protected: // Helper function which reflow the anonymous div frame. diff --git a/layout/forms/nsRangeFrame.cpp b/layout/forms/nsRangeFrame.cpp index c8fbe3772b23..5b74a9e6d274 100644 --- a/layout/forms/nsRangeFrame.cpp +++ b/layout/forms/nsRangeFrame.cpp @@ -11,6 +11,7 @@ #include "nsContentCreatorFunctions.h" #include "nsContentList.h" #include "nsContentUtils.h" +#include "nsCSSPseudoElements.h" #include "nsCSSRendering.h" #include "nsFormControlFrame.h" #include "nsIContent.h" @@ -86,7 +87,7 @@ nsRangeFrame::Init(nsIContent* aContent, mOuterFocusStyle = styleSet->ProbePseudoElementStyle(aContent->AsElement(), - nsCSSPseudoElements::ePseudo_mozFocusOuter, + CSSPseudoElementType::mozFocusOuter, StyleContext()); return nsContainerFrame::Init(aContent, aParent, aPrevInFlow); @@ -110,7 +111,7 @@ nsRangeFrame::DestroyFrom(nsIFrame* aDestructRoot) nsresult nsRangeFrame::MakeAnonymousDiv(Element** aResult, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, nsTArray& aElements) { nsCOMPtr doc = mContent->GetComposedDoc(); @@ -138,19 +139,19 @@ nsRangeFrame::CreateAnonymousContent(nsTArray& aElements) // Create the ::-moz-range-track pseuto-element (a div): rv = MakeAnonymousDiv(getter_AddRefs(mTrackDiv), - nsCSSPseudoElements::ePseudo_mozRangeTrack, + CSSPseudoElementType::mozRangeTrack, aElements); NS_ENSURE_SUCCESS(rv, rv); // Create the ::-moz-range-progress pseudo-element (a div): rv = MakeAnonymousDiv(getter_AddRefs(mProgressDiv), - nsCSSPseudoElements::ePseudo_mozRangeProgress, + CSSPseudoElementType::mozRangeProgress, aElements); NS_ENSURE_SUCCESS(rv, rv); // Create the ::-moz-range-thumb pseudo-element (a div): rv = MakeAnonymousDiv(getter_AddRefs(mThumbDiv), - nsCSSPseudoElements::ePseudo_mozRangeThumb, + CSSPseudoElementType::mozRangeThumb, aElements); return rv; } @@ -894,17 +895,17 @@ nsRangeFrame::ShouldUseNativeStyle() const } Element* -nsRangeFrame::GetPseudoElement(nsCSSPseudoElements::Type aType) +nsRangeFrame::GetPseudoElement(CSSPseudoElementType aType) { - if (aType == nsCSSPseudoElements::ePseudo_mozRangeTrack) { + if (aType == CSSPseudoElementType::mozRangeTrack) { return mTrackDiv; } - if (aType == nsCSSPseudoElements::ePseudo_mozRangeThumb) { + if (aType == CSSPseudoElementType::mozRangeThumb) { return mThumbDiv; } - if (aType == nsCSSPseudoElements::ePseudo_mozRangeProgress) { + if (aType == CSSPseudoElementType::mozRangeProgress) { return mProgressDiv; } diff --git a/layout/forms/nsRangeFrame.h b/layout/forms/nsRangeFrame.h index 63b7a5086172..80412247757d 100644 --- a/layout/forms/nsRangeFrame.h +++ b/layout/forms/nsRangeFrame.h @@ -27,6 +27,7 @@ class nsRangeFrame : public nsContainerFrame, explicit nsRangeFrame(nsStyleContext* aContext); virtual ~nsRangeFrame(); + typedef mozilla::CSSPseudoElementType CSSPseudoElementType; typedef mozilla::dom::Element Element; public: @@ -147,12 +148,12 @@ public: */ void UpdateForValueChange(); - virtual Element* GetPseudoElement(nsCSSPseudoElements::Type aType) override; + virtual Element* GetPseudoElement(CSSPseudoElementType aType) override; private: nsresult MakeAnonymousDiv(Element** aResult, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, nsTArray& aElements); // Helper function which reflows the anonymous div frames. diff --git a/layout/forms/nsTextControlFrame.cpp b/layout/forms/nsTextControlFrame.cpp index 36e8e66e7a9c..e29b76e11806 100644 --- a/layout/forms/nsTextControlFrame.cpp +++ b/layout/forms/nsTextControlFrame.cpp @@ -10,6 +10,7 @@ #include "nsTextControlFrame.h" #include "nsIPlaintextEditor.h" #include "nsCaret.h" +#include "nsCSSPseudoElements.h" #include "nsGenericHTMLElement.h" #include "nsIEditor.h" #include "nsIEditorIMESupport.h" @@ -346,8 +347,7 @@ nsTextControlFrame::CreateAnonymousContent(nsTArray& aElements) NS_ENSURE_TRUE(placeholderNode, NS_ERROR_OUT_OF_MEMORY); // Associate ::-moz-placeholder pseudo-element with the placeholder node. - nsCSSPseudoElements::Type pseudoType = - nsCSSPseudoElements::ePseudo_mozPlaceholder; + CSSPseudoElementType pseudoType = CSSPseudoElementType::mozPlaceholder; RefPtr placeholderStyleContext = PresContext()->StyleSet()->ResolvePseudoElementStyle( @@ -1444,9 +1444,9 @@ nsTextControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, } mozilla::dom::Element* -nsTextControlFrame::GetPseudoElement(nsCSSPseudoElements::Type aType) +nsTextControlFrame::GetPseudoElement(CSSPseudoElementType aType) { - if (aType == nsCSSPseudoElements::ePseudo_mozPlaceholder) { + if (aType == CSSPseudoElementType::mozPlaceholder) { nsCOMPtr txtCtrl = do_QueryInterface(GetContent()); return txtCtrl->GetPlaceholderNode(); } diff --git a/layout/forms/nsTextControlFrame.h b/layout/forms/nsTextControlFrame.h index 0157d3b4a785..9e12342cf1c2 100644 --- a/layout/forms/nsTextControlFrame.h +++ b/layout/forms/nsTextControlFrame.h @@ -19,6 +19,7 @@ class EditorInitializerEntryTracker; class nsTextEditorState; class nsIEditor; namespace mozilla { +enum class CSSPseudoElementType : uint8_t; namespace dom { class Element; } // namespace dom @@ -98,10 +99,11 @@ public: const nsRect& aDirtyRect, const nsDisplayListSet& aLists) override; - virtual mozilla::dom::Element* GetPseudoElement(nsCSSPseudoElements::Type aType) override; + virtual mozilla::dom::Element* + GetPseudoElement(mozilla::CSSPseudoElementType aType) override; //==== BEGIN NSIFORMCONTROLFRAME - virtual void SetFocus(bool aOn , bool aRepaint) override; + virtual void SetFocus(bool aOn , bool aRepaint) override; virtual nsresult SetFormProperty(nsIAtom* aName, const nsAString& aValue) override; //==== END NSIFORMCONTROLFRAME diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index 0018bb94f17c..a1dca21953bc 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -6897,9 +6897,9 @@ nsBlockFrame::CreateBulletFrameForListItem(bool aCreateBulletList, { nsIPresShell* shell = PresContext()->PresShell(); - nsCSSPseudoElements::Type pseudoType = aCreateBulletList ? - nsCSSPseudoElements::ePseudo_mozListBullet : - nsCSSPseudoElements::ePseudo_mozListNumber; + CSSPseudoElementType pseudoType = aCreateBulletList ? + CSSPseudoElementType::mozListBullet : + CSSPseudoElementType::mozListNumber; nsStyleContext* parentStyle = CorrectStyleParentFrame(this, diff --git a/layout/generic/nsBlockFrame.h b/layout/generic/nsBlockFrame.h index 2eaeae08afca..51cafa255514 100644 --- a/layout/generic/nsBlockFrame.h +++ b/layout/generic/nsBlockFrame.h @@ -367,7 +367,7 @@ protected: { return aPresContext->StyleSet()-> ProbePseudoElementStyle(mContent->AsElement(), - nsCSSPseudoElements::ePseudo_firstLetter, + mozilla::CSSPseudoElementType::firstLetter, mStyleContext); } #endif diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 98088a84a902..d9c4448f66b0 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -24,6 +24,7 @@ #include "nsPlaceholderFrame.h" #include "nsIContent.h" #include "nsContentUtils.h" +#include "nsCSSPseudoElements.h" #include "nsIAtom.h" #include "nsString.h" #include "nsReadableUtils.h" @@ -9121,13 +9122,13 @@ nsIFrame::IsPseudoStackingContextFromStyle() { } Element* -nsIFrame::GetPseudoElement(nsCSSPseudoElements::Type aType) +nsIFrame::GetPseudoElement(CSSPseudoElementType aType) { nsIFrame* frame = nullptr; - if (aType == nsCSSPseudoElements::ePseudo_before) { + if (aType == CSSPseudoElementType::before) { frame = nsLayoutUtils::GetBeforeFrame(this); - } else if (aType == nsCSSPseudoElements::ePseudo_after) { + } else if (aType == CSSPseudoElementType::after) { frame = nsLayoutUtils::GetAfterFrame(this); } @@ -9137,7 +9138,7 @@ nsIFrame::GetPseudoElement(nsCSSPseudoElements::Type aType) return content->AsElement(); } } - + return nullptr; } diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 29e238710730..3db07f136fa2 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -90,6 +90,7 @@ struct CharacterDataChangeInfo; namespace mozilla { +enum class CSSPseudoElementType : uint8_t; class EventStates; namespace layers { @@ -3094,7 +3095,8 @@ public: * generated and which corresponds to the specified pseudo-element type, * or nullptr if there is no such anonymous content. */ - virtual mozilla::dom::Element* GetPseudoElement(nsCSSPseudoElements::Type aType); + virtual mozilla::dom::Element* + GetPseudoElement(mozilla::CSSPseudoElementType aType); bool BackfaceIsHidden() { return StyleDisplay()->BackfaceIsHidden(); diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index c09338014e8d..f4cb0b480d83 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -3807,7 +3807,7 @@ nsTextPaintStyle::InitSelectionColorsAndShadow() RefPtr sc = nullptr; sc = mPresContext->StyleSet()-> ProbePseudoElementStyle(selectionElement, - nsCSSPseudoElements::ePseudo_mozSelection, + CSSPseudoElementType::mozSelection, mFrame->StyleContext()); // Use -moz-selection pseudo class. if (sc) { diff --git a/layout/inspector/inDOMUtils.cpp b/layout/inspector/inDOMUtils.cpp index 5c15eb3d2194..a85d38aa939b 100644 --- a/layout/inspector/inDOMUtils.cpp +++ b/layout/inspector/inDOMUtils.cpp @@ -1194,8 +1194,9 @@ inDOMUtils::GetCSSPseudoElementNames(uint32_t* aLength, char16_t*** aNames) { nsTArray array; - for (int i = 0; i < nsCSSPseudoElements::ePseudo_PseudoElementCount; ++i) { - nsCSSPseudoElements::Type type = static_cast(i); + const uint8_t pseudoCount = static_cast(CSSPseudoElementType::Count); + for (uint8_t i = 0; i < pseudoCount; ++i) { + CSSPseudoElementType type = static_cast(i); if (!nsCSSPseudoElements::PseudoElementIsUASheetOnly(type)) { nsIAtom* atom = nsCSSPseudoElements::GetPseudoAtom(type); array.AppendElement(atom); diff --git a/layout/mathml/nsMathMLFrame.cpp b/layout/mathml/nsMathMLFrame.cpp index 7a2c578f3116..aec0b2516318 100644 --- a/layout/mathml/nsMathMLFrame.cpp +++ b/layout/mathml/nsMathMLFrame.cpp @@ -98,8 +98,8 @@ nsMathMLFrame::ResolveMathMLCharStyle(nsPresContext* aPresContext, nsStyleContext* aParentStyleContext, nsMathMLChar* aMathMLChar) { - nsCSSPseudoElements::Type pseudoType = - nsCSSPseudoElements::ePseudo_mozMathAnonymous; // savings + CSSPseudoElementType pseudoType = + CSSPseudoElementType::mozMathAnonymous; // savings RefPtr newStyleContext; newStyleContext = aPresContext->StyleSet()-> ResolvePseudoElementStyle(aContent->AsElement(), pseudoType, diff --git a/layout/reftests/marquee/1160342-1.html b/layout/reftests/marquee/1160342-1.html new file mode 100644 index 000000000000..85e7215fbbab --- /dev/null +++ b/layout/reftests/marquee/1160342-1.html @@ -0,0 +1,10 @@ + + +Bug 1160342 - Implement marquee using mutation observers + + + +This text should be visible + + + diff --git a/layout/reftests/marquee/1160342-2.html b/layout/reftests/marquee/1160342-2.html new file mode 100644 index 000000000000..99b288568bac --- /dev/null +++ b/layout/reftests/marquee/1160342-2.html @@ -0,0 +1,10 @@ + + +Bug 1160342 - Implement marquee using mutation observers + + + +This text should be visible + + + diff --git a/layout/reftests/marquee/1160342-ref.html b/layout/reftests/marquee/1160342-ref.html new file mode 100644 index 000000000000..d56c90642aad --- /dev/null +++ b/layout/reftests/marquee/1160342-ref.html @@ -0,0 +1,10 @@ + + +Bug 1160342 - Implement marquee using mutation observers + + + +This text should be visible + + + diff --git a/layout/reftests/marquee/reftest.list b/layout/reftests/marquee/reftest.list index 298a02b0b5d8..932298a272c7 100644 --- a/layout/reftests/marquee/reftest.list +++ b/layout/reftests/marquee/reftest.list @@ -7,3 +7,5 @@ fuzzy-if(Android&&AndroidVersion>=15,8,220) == 413027-4.html 413027-4-ref.html fuzzy-if(Android&&AndroidVersion>=15,8,30) == 425247-1.html 425247-1-ref.html fuzzy-if(Android&&AndroidVersion>=15,8,30) == 425247-2.html 425247-2-ref.html random == 429849-1.html 429849-1-ref.html # bug 432288 +== 1160342-1.html 1160342-ref.html +== 1160342-2.html 1160342-ref.html diff --git a/layout/style/AnimationCommon.cpp b/layout/style/AnimationCommon.cpp index 79926224c72f..330086493cf0 100644 --- a/layout/style/AnimationCommon.cpp +++ b/layout/style/AnimationCommon.cpp @@ -68,7 +68,7 @@ CommonAnimationManager::RemoveAllElementCollections() AnimationCollection* CommonAnimationManager::GetAnimationCollection(dom::Element *aElement, - nsCSSPseudoElements::Type + CSSPseudoElementType aPseudoType, bool aCreateIfNeeded) { @@ -78,11 +78,11 @@ CommonAnimationManager::GetAnimationCollection(dom::Element *aElement, } nsIAtom *propName; - if (aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) { + if (aPseudoType == CSSPseudoElementType::NotPseudo) { propName = GetAnimationsAtom(); - } else if (aPseudoType == nsCSSPseudoElements::ePseudo_before) { + } else if (aPseudoType == CSSPseudoElementType::before) { propName = GetAnimationsBeforeAtom(); - } else if (aPseudoType == nsCSSPseudoElements::ePseudo_after) { + } else if (aPseudoType == CSSPseudoElementType::after) { propName = GetAnimationsAfterAtom(); } else { NS_ASSERTION(!aCreateIfNeeded, @@ -117,7 +117,7 @@ CommonAnimationManager::GetAnimationCollection(dom::Element *aElement, AnimationCollection* CommonAnimationManager::GetAnimationCollection(const nsIFrame* aFrame) { - Maybe> pseudoElement = + Maybe> pseudoElement = EffectCompositor::GetAnimationElementAndPseudoForFrame(aFrame); if (!pseudoElement) { return nullptr; @@ -152,15 +152,15 @@ CommonAnimationManager::ExtractComputedValueForTransition( } /*static*/ nsString -AnimationCollection::PseudoTypeAsString(nsCSSPseudoElements::Type aPseudoType) +AnimationCollection::PseudoTypeAsString(CSSPseudoElementType aPseudoType) { switch (aPseudoType) { - case nsCSSPseudoElements::ePseudo_before: + case CSSPseudoElementType::before: return NS_LITERAL_STRING("::before"); - case nsCSSPseudoElements::ePseudo_after: + case CSSPseudoElementType::after: return NS_LITERAL_STRING("::after"); default: - MOZ_ASSERT(aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement, + MOZ_ASSERT(aPseudoType == CSSPseudoElementType::NotPseudo, "Unexpected pseudo type"); return EmptyString(); } diff --git a/layout/style/AnimationCommon.h b/layout/style/AnimationCommon.h index 9892acdafbd2..2b492827ee09 100644 --- a/layout/style/AnimationCommon.h +++ b/layout/style/AnimationCommon.h @@ -83,7 +83,7 @@ public: // by this class for the given |aElement| and |aPseudoType|. AnimationCollection* GetAnimationCollection(dom::Element *aElement, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, bool aCreateIfNeeded); // Given the frame |aFrame| with possibly animated content, finds its @@ -174,20 +174,20 @@ public: mElementProperty == nsGkAtoms::animationsOfAfterProperty; } - nsCSSPseudoElements::Type PseudoElementType() const + CSSPseudoElementType PseudoElementType() const { if (IsForElement()) { - return nsCSSPseudoElements::ePseudo_NotPseudoElement; + return CSSPseudoElementType::NotPseudo; } if (IsForBeforePseudo()) { - return nsCSSPseudoElements::ePseudo_before; + return CSSPseudoElementType::before; } MOZ_ASSERT(IsForAfterPseudo(), "::before & ::after should be the only pseudo-elements here"); - return nsCSSPseudoElements::ePseudo_after; + return CSSPseudoElementType::after; } - static nsString PseudoTypeAsString(nsCSSPseudoElements::Type aPseudoType); + static nsString PseudoTypeAsString(CSSPseudoElementType aPseudoType); dom::Element* GetElementToRestyle() const; @@ -235,11 +235,11 @@ class OwningElementRef final public: OwningElementRef() : mElement(nullptr) - , mPseudoType(nsCSSPseudoElements::ePseudo_NotPseudoElement) + , mPseudoType(CSSPseudoElementType::NotPseudo) { } OwningElementRef(dom::Element& aElement, - nsCSSPseudoElements::Type aPseudoType) + CSSPseudoElementType aPseudoType) : mElement(&aElement) , mPseudoType(aPseudoType) { } @@ -259,15 +259,15 @@ public: return nsContentUtils::PositionIsBefore(mElement, aOther.mElement); } - return mPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement || - (mPseudoType == nsCSSPseudoElements::ePseudo_before && - aOther.mPseudoType == nsCSSPseudoElements::ePseudo_after); + return mPseudoType == CSSPseudoElementType::NotPseudo || + (mPseudoType == CSSPseudoElementType::before && + aOther.mPseudoType == CSSPseudoElementType::after); } bool IsSet() const { return !!mElement; } void GetElement(dom::Element*& aElement, - nsCSSPseudoElements::Type& aPseudoType) const { + CSSPseudoElementType& aPseudoType) const { aElement = mElement; aPseudoType = mPseudoType; } @@ -276,7 +276,7 @@ public: private: dom::Element* MOZ_NON_OWNING_REF mElement; - nsCSSPseudoElements::Type mPseudoType; + CSSPseudoElementType mPseudoType; }; template diff --git a/layout/style/StyleAnimationValue.cpp b/layout/style/StyleAnimationValue.cpp index bfe8936b397a..8b17fe8a4966 100644 --- a/layout/style/StyleAnimationValue.cpp +++ b/layout/style/StyleAnimationValue.cpp @@ -19,6 +19,7 @@ #include "nsStyleSet.h" #include "nsComputedDOMStyle.h" #include "nsCSSParser.h" +#include "nsCSSPseudoElements.h" #include "mozilla/css/Declaration.h" #include "mozilla/dom/Element.h" #include "mozilla/FloatingPoint.h" @@ -2526,7 +2527,7 @@ BuildStyleRule(nsCSSProperty aProperty, inline already_AddRefed LookupStyleContext(dom::Element* aElement, - nsCSSPseudoElements::Type aPseudoType) + CSSPseudoElementType aPseudoType) { nsIDocument* doc = aElement->GetCurrentDoc(); nsIPresShell* shell = doc->GetShell(); @@ -2535,7 +2536,7 @@ LookupStyleContext(dom::Element* aElement, } nsIAtom* pseudo = - aPseudoType < nsCSSPseudoElements::ePseudo_PseudoElementCount ? + aPseudoType < CSSPseudoElementType::Count ? nsCSSPseudoElements::GetPseudoAtom(aPseudoType) : nullptr; return nsComputedDOMStyle::GetStyleContextForElement(aElement, pseudo, shell); } @@ -2543,7 +2544,7 @@ LookupStyleContext(dom::Element* aElement, /* static */ bool StyleAnimationValue::ComputeValue(nsCSSProperty aProperty, dom::Element* aTargetElement, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, const nsAString& aSpecifiedValue, bool aUseSVGMode, StyleAnimationValue& aComputedValue, @@ -2595,7 +2596,7 @@ StyleAnimationValue::ComputeValue(nsCSSProperty aProperty, StyleAnimationValue::ComputeValues(nsCSSProperty aProperty, nsCSSProps::EnabledState aEnabledState, dom::Element* aTargetElement, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, const nsAString& aSpecifiedValue, bool aUseSVGMode, nsTArray& aResult) @@ -2625,7 +2626,7 @@ StyleAnimationValue::ComputeValues( nsCSSProperty aProperty, nsCSSProps::EnabledState aEnabledState, dom::Element* aTargetElement, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, css::StyleRule* aStyleRule, nsTArray& aValues, bool* aIsContextSensitive) diff --git a/layout/style/StyleAnimationValue.h b/layout/style/StyleAnimationValue.h index 1af9a922c4ee..09798cd9a76a 100644 --- a/layout/style/StyleAnimationValue.h +++ b/layout/style/StyleAnimationValue.h @@ -14,7 +14,6 @@ #include "nsCoord.h" #include "nsColor.h" #include "nsCSSProps.h" -#include "nsCSSPseudoElements.h" #include "nsCSSValue.h" class nsIFrame; @@ -31,6 +30,7 @@ namespace dom { class Element; } // namespace dom +enum class CSSPseudoElementType : uint8_t; struct PropertyStyleAnimationValuePair; /** @@ -156,7 +156,7 @@ public: */ static bool ComputeValue(nsCSSProperty aProperty, mozilla::dom::Element* aTargetElement, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, const nsAString& aSpecifiedValue, bool aUseSVGMode, StyleAnimationValue& aComputedValue, @@ -175,7 +175,7 @@ public: static bool ComputeValues(nsCSSProperty aProperty, nsCSSProps::EnabledState aEnabledState, mozilla::dom::Element* aTargetElement, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, const nsAString& aSpecifiedValue, bool aUseSVGMode, nsTArray& aResult); @@ -403,7 +403,7 @@ private: static bool ComputeValues(nsCSSProperty aProperty, nsCSSProps::EnabledState aEnabledState, mozilla::dom::Element* aTargetElement, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, mozilla::css::StyleRule* aStyleRule, nsTArray& aValues, bool* aIsContextSensitive); diff --git a/layout/style/StyleRule.cpp b/layout/style/StyleRule.cpp index e72c4198cc79..57dbea4bd1d7 100644 --- a/layout/style/StyleRule.cpp +++ b/layout/style/StyleRule.cpp @@ -23,7 +23,6 @@ #include "nsDOMCSSDeclaration.h" #include "nsNameSpaceManager.h" #include "nsXMLNameSpaceMap.h" -#include "nsCSSPseudoElements.h" #include "nsCSSPseudoClasses.h" #include "nsCSSAnonBoxes.h" #include "nsTArray.h" @@ -315,11 +314,9 @@ nsCSSSelector::nsCSSSelector(void) mNext(nullptr), mNameSpace(kNameSpaceID_Unknown), mOperator(0), - mPseudoType(nsCSSPseudoElements::ePseudo_NotPseudoElement) + mPseudoType(CSSPseudoElementType::NotPseudo) { MOZ_COUNT_CTOR(nsCSSSelector); - static_assert(nsCSSPseudoElements::ePseudo_MAX < INT16_MAX, - "nsCSSPseudoElements::Type values overflow mPseudoType"); } nsCSSSelector* @@ -334,7 +331,7 @@ nsCSSSelector::Clone(bool aDeepNext, bool aDeepNegations) const result->mCasedTag = mCasedTag; result->mOperator = mOperator; result->mPseudoType = mPseudoType; - + NS_IF_CLONE(mIDList); NS_IF_CLONE(mClassList); NS_IF_CLONE(mPseudoClassList); @@ -492,7 +489,7 @@ int32_t nsCSSSelector::CalcWeightWithoutNegations() const #ifdef MOZ_XUL MOZ_ASSERT(!(IsPseudoElement() && - PseudoType() != nsCSSPseudoElements::ePseudo_XULTree && + PseudoType() != CSSPseudoElementType::XULTree && mClassList), "If non-XUL-tree pseudo-elements can have class selectors " "after them, specificity calculation must be updated"); @@ -517,7 +514,7 @@ int32_t nsCSSSelector::CalcWeightWithoutNegations() const #ifdef MOZ_XUL // XUL tree pseudo-elements abuse mClassList to store some private // data; ignore that. - if (PseudoType() == nsCSSPseudoElements::ePseudo_XULTree) { + if (PseudoType() == CSSPseudoElementType::XULTree) { list = nullptr; } #endif diff --git a/layout/style/StyleRule.h b/layout/style/StyleRule.h index 212110d9f00c..9610b660ec48 100644 --- a/layout/style/StyleRule.h +++ b/layout/style/StyleRule.h @@ -17,14 +17,15 @@ #include "nsString.h" #include "nsCOMPtr.h" -#include "nsCSSPseudoElements.h" #include "nsCSSPseudoClasses.h" +#include "nsCSSPseudoElements.h" #include "nsIStyleRule.h" class nsIAtom; struct nsCSSSelectorList; namespace mozilla { +enum class CSSPseudoElementType : uint8_t; class CSSStyleSheet; } // namespace mozilla @@ -178,7 +179,7 @@ public: bool aAppend = false) const; bool IsRestrictedSelector() const { - return PseudoType() == nsCSSPseudoElements::ePseudo_NotPseudoElement; + return PseudoType() == mozilla::CSSPseudoElementType::NotPseudo; } #ifdef DEBUG @@ -208,14 +209,9 @@ private: public: // Get and set the selector's pseudo type - nsCSSPseudoElements::Type PseudoType() const { - return static_cast(mPseudoType); - } - void SetPseudoType(nsCSSPseudoElements::Type aType) { - NS_ASSERTION(static_cast(aType) >= INT16_MIN && - static_cast(aType) <= INT16_MAX, - "Out of bounds - this will overflow mPseudoType"); - mPseudoType = static_cast(aType); + mozilla::CSSPseudoElementType PseudoType() const { return mPseudoType; } + void SetPseudoType(mozilla::CSSPseudoElementType aType) { + mPseudoType = aType; } size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; @@ -236,8 +232,9 @@ public: int32_t mNameSpace; char16_t mOperator; private: - // int16_t to make sure it packs well with mOperator - int16_t mPseudoType; + // The underlying type of CSSPseudoElementType is uint8_t and + // it packs well with mOperator. (char16_t + uint8_t is less than 32bits.) + mozilla::CSSPseudoElementType mPseudoType; nsCSSSelector(const nsCSSSelector& aCopy) = delete; nsCSSSelector& operator=(const nsCSSSelector& aCopy) = delete; diff --git a/layout/style/nsAnimationManager.cpp b/layout/style/nsAnimationManager.cpp index 759df682bd99..5225cb12bc8a 100644 --- a/layout/style/nsAnimationManager.cpp +++ b/layout/style/nsAnimationManager.cpp @@ -168,7 +168,7 @@ CSSAnimation::QueueEvents() } dom::Element* owningElement; - nsCSSPseudoElements::Type owningPseudoType; + CSSPseudoElementType owningPseudoType; mOwningElement.GetElement(owningElement, owningPseudoType); MOZ_ASSERT(owningElement, "Owning element should be set"); @@ -488,7 +488,7 @@ nsAnimationManager::UpdateAnimations(nsStyleContext* aStyleContext, void nsAnimationManager::StopAnimationsForElement( mozilla::dom::Element* aElement, - nsCSSPseudoElements::Type aPseudoType) + mozilla::CSSPseudoElementType aPseudoType) { MOZ_ASSERT(aElement); AnimationCollection* collection = diff --git a/layout/style/nsAnimationManager.h b/layout/style/nsAnimationManager.h index 0b1280b71a50..7869e5907461 100644 --- a/layout/style/nsAnimationManager.h +++ b/layout/style/nsAnimationManager.h @@ -9,7 +9,6 @@ #include "mozilla/ContentEvents.h" #include "mozilla/EventForwards.h" #include "AnimationCommon.h" -#include "nsCSSPseudoElements.h" #include "mozilla/dom/Animation.h" #include "mozilla/MemoryReporting.h" #include "mozilla/TimeStamp.h" @@ -26,6 +25,8 @@ class KeyframeEffectReadOnly; class Promise; } /* namespace dom */ +enum class CSSPseudoElementType : uint8_t; + struct AnimationEventInfo { RefPtr mElement; RefPtr mAnimation; @@ -33,7 +34,7 @@ struct AnimationEventInfo { TimeStamp mTimeStamp; AnimationEventInfo(dom::Element* aElement, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, EventMessage aMessage, const nsSubstring& aAnimationName, const StickyTimeDuration& aElapsedTime, @@ -322,7 +323,7 @@ public: // rather than the element for the generated content for animations on // ::before and ::after. void StopAnimationsForElement(mozilla::dom::Element* aElement, - nsCSSPseudoElements::Type aPseudoType); + mozilla::CSSPseudoElementType aPseudoType); bool IsAnimationManager() override { return true; diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index 40d03ec2b07b..b481bad14bb8 100644 --- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -753,7 +753,7 @@ protected: bool aIsNegated, nsIAtom** aPseudoElement, nsAtomList** aPseudoElementArgs, - nsCSSPseudoElements::Type* aPseudoElementType); + CSSPseudoElementType* aPseudoElementType); nsSelectorParsingStatus ParseAttributeSelector(int32_t& aDataMask, nsCSSSelector& aSelector); @@ -5827,7 +5827,7 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, bool aIsNegated, nsIAtom** aPseudoElement, nsAtomList** aPseudoElementArgs, - nsCSSPseudoElements::Type* aPseudoElementType) + CSSPseudoElementType* aPseudoElementType) { NS_ASSERTION(aIsNegated || (aPseudoElement && aPseudoElementArgs), "expected location to store pseudo element"); @@ -5867,7 +5867,7 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, // stash away some info about this pseudo so we only have to get it once. bool isTreePseudo = false; - nsCSSPseudoElements::Type pseudoElementType = + CSSPseudoElementType pseudoElementType = nsCSSPseudoElements::GetPseudoType(pseudo); nsCSSPseudoClasses::Type pseudoClassType = nsCSSPseudoClasses::GetPseudoType(pseudo); @@ -5875,7 +5875,7 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, nsCSSPseudoClasses::IsUserActionPseudoClass(pseudoClassType); if (!AgentRulesEnabled() && - ((pseudoElementType < nsCSSPseudoElements::ePseudo_PseudoElementCount && + ((pseudoElementType < CSSPseudoElementType::Count && nsCSSPseudoElements::PseudoElementIsUASheetOnly(pseudoElementType)) || (pseudoClassType != nsCSSPseudoClasses::ePseudoClass_NotPseudoClass && nsCSSPseudoClasses::PseudoClassIsUASheetOnly(pseudoClassType)))) { @@ -5887,17 +5887,17 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, // We currently allow :-moz-placeholder and ::-moz-placeholder. We have to // be a bit stricter regarding the pseudo-element parsing rules. - if (pseudoElementType == nsCSSPseudoElements::ePseudo_mozPlaceholder && + if (pseudoElementType == CSSPseudoElementType::mozPlaceholder && pseudoClassType == nsCSSPseudoClasses::ePseudoClass_mozPlaceholder) { if (parsingPseudoElement) { pseudoClassType = nsCSSPseudoClasses::ePseudoClass_NotPseudoClass; } else { - pseudoElementType = nsCSSPseudoElements::ePseudo_NotPseudoElement; + pseudoElementType = CSSPseudoElementType::NotPseudo; } } #ifdef MOZ_XUL - isTreePseudo = (pseudoElementType == nsCSSPseudoElements::ePseudo_XULTree); + isTreePseudo = (pseudoElementType == CSSPseudoElementType::XULTree); // If a tree pseudo-element is using the function syntax, it will // get isTree set here and will pass the check below that only // allows functions if they are in our list of things allowed to be @@ -5907,18 +5907,17 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, // desired. bool isTree = (eCSSToken_Function == mToken.mType) && isTreePseudo; #endif - bool isPseudoElement = - (pseudoElementType < nsCSSPseudoElements::ePseudo_PseudoElementCount); + bool isPseudoElement = (pseudoElementType < CSSPseudoElementType::Count); // anonymous boxes are only allowed if they're the tree boxes or we have // enabled agent rules bool isAnonBox = isTreePseudo || - (pseudoElementType == nsCSSPseudoElements::ePseudo_AnonBox && + (pseudoElementType == CSSPseudoElementType::AnonBox && AgentRulesEnabled()); bool isPseudoClass = (pseudoClassType != nsCSSPseudoClasses::ePseudoClass_NotPseudoClass); NS_ASSERTION(!isPseudoClass || - pseudoElementType == nsCSSPseudoElements::ePseudo_NotPseudoElement, + pseudoElementType == CSSPseudoElementType::NotPseudo, "Why is this atom both a pseudo-class and a pseudo-element?"); NS_ASSERTION(isPseudoClass + isPseudoElement + isAnonBox <= 1, "Shouldn't be more than one of these"); @@ -5972,7 +5971,7 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask, } else if (!parsingPseudoElement && isPseudoClass) { if (aSelector.IsPseudoElement()) { - nsCSSPseudoElements::Type type = aSelector.PseudoType(); + CSSPseudoElementType type = aSelector.PseudoType(); if (!nsCSSPseudoElements::PseudoElementSupportsUserActionState(type)) { // We only allow user action pseudo-classes on certain pseudo-elements. REPORT_UNEXPECTED_TOKEN(PEPseudoSelNoUserActionPC); @@ -6413,8 +6412,7 @@ CSSParserImpl::ParseSelector(nsCSSSelectorList* aList, nsCSSSelector* selector = aList->AddSelector(aPrevCombinator); nsCOMPtr pseudoElement; nsAutoPtr pseudoElementArgs; - nsCSSPseudoElements::Type pseudoElementType = - nsCSSPseudoElements::ePseudo_NotPseudoElement; + CSSPseudoElementType pseudoElementType = CSSPseudoElementType::NotPseudo; int32_t dataMask = 0; nsSelectorParsingStatus parsingStatus = @@ -6433,7 +6431,7 @@ CSSParserImpl::ParseSelector(nsCSSSelectorList* aList, getter_Transfers(pseudoElementArgs), &pseudoElementType); if (pseudoElement && - pseudoElementType != nsCSSPseudoElements::ePseudo_AnonBox) { + pseudoElementType != CSSPseudoElementType::AnonBox) { // Pseudo-elements other than anonymous boxes are represented with // a special ':' combinator. @@ -6481,7 +6479,7 @@ CSSParserImpl::ParseSelector(nsCSSSelectorList* aList, return false; } - if (pseudoElementType == nsCSSPseudoElements::ePseudo_AnonBox) { + if (pseudoElementType == CSSPseudoElementType::AnonBox) { // We got an anonymous box pseudo-element; it must be the only // thing in this selector group. if (selector->mNext || !IsUniversalSelector(*selector)) { diff --git a/layout/style/nsCSSPseudoElements.cpp b/layout/style/nsCSSPseudoElements.cpp index fd140f75cd29..7f5d85e39bdd 100644 --- a/layout/style/nsCSSPseudoElements.cpp +++ b/layout/style/nsCSSPseudoElements.cpp @@ -67,46 +67,45 @@ nsCSSPseudoElements::IsCSS2PseudoElement(nsIAtom *aAtom) aAtom == nsCSSPseudoElements::firstLetter || aAtom == nsCSSPseudoElements::firstLine; NS_ASSERTION(nsCSSAnonBoxes::IsAnonBox(aAtom) || - result == - PseudoElementHasFlags(GetPseudoType(aAtom), CSS_PSEUDO_ELEMENT_IS_CSS2), + result == PseudoElementHasFlags(GetPseudoType(aAtom), + CSS_PSEUDO_ELEMENT_IS_CSS2), "result doesn't match flags"); return result; } -/* static */ nsCSSPseudoElements::Type +/* static */ CSSPseudoElementType nsCSSPseudoElements::GetPseudoType(nsIAtom *aAtom) { - for (uint32_t i = 0; i < ArrayLength(CSSPseudoElements_info); ++i) { + for (uint8_t i = 0; i < ArrayLength(CSSPseudoElements_info); ++i) { if (*CSSPseudoElements_info[i].mAtom == aAtom) { - return Type(i); + return static_cast(i); } } if (nsCSSAnonBoxes::IsAnonBox(aAtom)) { #ifdef MOZ_XUL if (nsCSSAnonBoxes::IsTreePseudoElement(aAtom)) { - return ePseudo_XULTree; + return Type::XULTree; } #endif - return ePseudo_AnonBox; + return Type::AnonBox; } - return ePseudo_NotPseudoElement; + return Type::NotPseudo; } /* static */ nsIAtom* nsCSSPseudoElements::GetPseudoAtom(Type aType) { - NS_ASSERTION(aType < nsCSSPseudoElements::ePseudo_PseudoElementCount, - "Unexpected type"); - return *CSSPseudoElements_info[aType].mAtom; + NS_ASSERTION(aType < Type::Count, "Unexpected type"); + return *CSSPseudoElements_info[static_cast(aType)].mAtom; } /* static */ uint32_t nsCSSPseudoElements::FlagsForPseudoElement(const Type aType) { - size_t index = static_cast(aType); + uint8_t index = static_cast(aType); NS_ASSERTION(index < ArrayLength(CSSPseudoElements_flags), "argument must be a pseudo-element"); return CSSPseudoElements_flags[index]; diff --git a/layout/style/nsCSSPseudoElements.h b/layout/style/nsCSSPseudoElements.h index dc4b910c8c4c..8d7ec5c6cfca 100644 --- a/layout/style/nsCSSPseudoElements.h +++ b/layout/style/nsCSSPseudoElements.h @@ -35,13 +35,37 @@ // Is content prevented from parsing selectors containing this pseudo-element? #define CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY (1<<4) +namespace mozilla { + +// The total count of CSSPseudoElement is less than 256, +// so use uint8_t as its underlying type. +enum class CSSPseudoElementType : uint8_t { + // If the actual pseudo-elements stop being first here, change + // GetPseudoType. +#define CSS_PSEUDO_ELEMENT(_name, _value_, _flags) \ + _name, +#include "nsCSSPseudoElementList.h" +#undef CSS_PSEUDO_ELEMENT + Count, + AnonBox = Count, +#ifdef MOZ_XUL + XULTree, +#endif + NotPseudo, + MAX +}; + +} // namespace mozilla + // Empty class derived from nsIAtom so that function signatures can // require an atom from this atom list. class nsICSSPseudoElement : public nsIAtom {}; -class nsCSSPseudoElements { -public: +class nsCSSPseudoElements +{ + typedef mozilla::CSSPseudoElementType Type; +public: static void AddRefAtoms(); static bool IsPseudoElement(nsIAtom *aAtom); @@ -53,25 +77,9 @@ public: #include "nsCSSPseudoElementList.h" #undef CSS_PSEUDO_ELEMENT - enum Type { - // If the actual pseudo-elements stop being first here, change - // GetPseudoType. -#define CSS_PSEUDO_ELEMENT(_name, _value_, _flags) \ - ePseudo_##_name, -#include "nsCSSPseudoElementList.h" -#undef CSS_PSEUDO_ELEMENT - ePseudo_PseudoElementCount, - ePseudo_AnonBox = ePseudo_PseudoElementCount, -#ifdef MOZ_XUL - ePseudo_XULTree, -#endif - ePseudo_NotPseudoElement, - ePseudo_MAX - }; - static Type GetPseudoType(nsIAtom* aAtom); - // Get the atom for a given Type. aType must be < ePseudo_PseudoElementCount + // Get the atom for a given Type. aType must be < CSSPseudoElementType::Count static nsIAtom* GetPseudoAtom(Type aType); static bool PseudoElementContainsElements(const Type aType) { @@ -79,14 +87,15 @@ public: } static bool PseudoElementSupportsStyleAttribute(const Type aType) { - MOZ_ASSERT(aType < ePseudo_PseudoElementCount); - return PseudoElementHasFlags(aType, CSS_PSEUDO_ELEMENT_SUPPORTS_STYLE_ATTRIBUTE); + MOZ_ASSERT(aType < Type::Count); + return PseudoElementHasFlags(aType, + CSS_PSEUDO_ELEMENT_SUPPORTS_STYLE_ATTRIBUTE); } static bool PseudoElementSupportsUserActionState(const Type aType); static bool PseudoElementIsUASheetOnly(const Type aType) { - MOZ_ASSERT(aType < ePseudo_PseudoElementCount); + MOZ_ASSERT(aType < Type::Count); return PseudoElementHasFlags(aType, CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY); } diff --git a/layout/style/nsCSSRuleProcessor.cpp b/layout/style/nsCSSRuleProcessor.cpp index 33f73518ae6d..7871e8922011 100644 --- a/layout/style/nsCSSRuleProcessor.cpp +++ b/layout/style/nsCSSRuleProcessor.cpp @@ -911,7 +911,7 @@ struct RuleCascadeData { RuleHash mRuleHash; RuleHash* - mPseudoElementRuleHashes[nsCSSPseudoElements::ePseudo_PseudoElementCount]; + mPseudoElementRuleHashes[static_cast(CSSPseudoElementType::Count)]; nsTArray mStateSelectors; EventStates mSelectorDocumentStates; PLDHashTable mClassSelectors; @@ -2644,7 +2644,9 @@ nsCSSRuleProcessor::RulesMatching(PseudoElementRuleProcessorData* aData) RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext); if (cascade) { - RuleHash* ruleHash = cascade->mPseudoElementRuleHashes[aData->mPseudoType]; + RuleHash* ruleHash = + cascade->mPseudoElementRuleHashes[static_cast( + aData->mPseudoType)]; if (ruleHash) { NodeMatchContext nodeContext(EventStates(), nsCSSRuleProcessor::IsLink(aData->mElement)); @@ -2714,7 +2716,7 @@ static inline nsRestyleHint RestyleHintForOp(char16_t oper) nsRestyleHint nsCSSRuleProcessor::HasStateDependentStyle(ElementDependentRuleProcessorData* aData, Element* aStatefulElement, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, EventStates aStateMask) { MOZ_ASSERT(!aData->mTreeMatchContext.mForScopedStyle, @@ -2722,7 +2724,7 @@ nsCSSRuleProcessor::HasStateDependentStyle(ElementDependentRuleProcessorData* aD "SelectorMatchesTree call"); bool isPseudoElement = - aPseudoType != nsCSSPseudoElements::ePseudo_NotPseudoElement; + aPseudoType != CSSPseudoElementType::NotPseudo; RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext); @@ -2806,7 +2808,7 @@ nsCSSRuleProcessor::HasStateDependentStyle(StateRuleProcessorData* aData) { return HasStateDependentStyle(aData, aData->mElement, - nsCSSPseudoElements::ePseudo_NotPseudoElement, + CSSPseudoElementType::NotPseudo, aData->mStateMask); } @@ -2888,7 +2890,7 @@ RestyleHintForSelectorWithAttributeChange(nsRestyleHint aCurrentHint, sel != aSelector; sel = sel->mNext) { MOZ_ASSERT(sel, "aSelector must be reachable from aRightmostSelector"); - if (sel->PseudoType() != nsCSSPseudoElements::ePseudo_NotPseudoElement) { + if (sel->PseudoType() != CSSPseudoElementType::NotPseudo) { return eRestyle_Subtree; } } @@ -3409,11 +3411,12 @@ AddRule(RuleSelectorPair* aRuleInfo, RuleCascadeData* aCascade) RuleCascadeData * const cascade = aCascade; // Build the rule hash. - nsCSSPseudoElements::Type pseudoType = aRuleInfo->mSelector->PseudoType(); - if (MOZ_LIKELY(pseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement)) { + CSSPseudoElementType pseudoType = aRuleInfo->mSelector->PseudoType(); + if (MOZ_LIKELY(pseudoType == CSSPseudoElementType::NotPseudo)) { cascade->mRuleHash.AppendRule(*aRuleInfo); - } else if (pseudoType < nsCSSPseudoElements::ePseudo_PseudoElementCount) { - RuleHash*& ruleHash = cascade->mPseudoElementRuleHashes[pseudoType]; + } else if (pseudoType < CSSPseudoElementType::Count) { + RuleHash*& ruleHash = + cascade->mPseudoElementRuleHashes[static_cast(pseudoType)]; if (!ruleHash) { ruleHash = new RuleHash(cascade->mQuirksMode); if (!ruleHash) { @@ -3426,7 +3429,7 @@ AddRule(RuleSelectorPair* aRuleInfo, RuleCascadeData* aCascade) NS_ASSERTION(aRuleInfo->mSelector->mNext->mOperator == ':', "Unexpected mNext combinator"); ruleHash->AppendRule(*aRuleInfo); - } else if (pseudoType == nsCSSPseudoElements::ePseudo_AnonBox) { + } else if (pseudoType == CSSPseudoElementType::AnonBox) { NS_ASSERTION(!aRuleInfo->mSelector->mCasedTag && !aRuleInfo->mSelector->mIDList && !aRuleInfo->mSelector->mClassList && @@ -3444,7 +3447,7 @@ AddRule(RuleSelectorPair* aRuleInfo, RuleCascadeData* aCascade) RuleValue(*aRuleInfo, 0, aCascade->mQuirksMode)); } else { #ifdef MOZ_XUL - NS_ASSERTION(pseudoType == nsCSSPseudoElements::ePseudo_XULTree, + NS_ASSERTION(pseudoType == CSSPseudoElementType::XULTree, "Unexpected pseudo type"); // Index doesn't matter here, since we'll just be walking these // rules in order; just pass 0. @@ -3459,8 +3462,8 @@ AddRule(RuleSelectorPair* aRuleInfo, RuleCascadeData* aCascade) for (nsCSSSelector* selector = aRuleInfo->mSelector; selector; selector = selector->mNext) { if (selector->IsPseudoElement()) { - nsCSSPseudoElements::Type pseudo = selector->PseudoType(); - if (pseudo >= nsCSSPseudoElements::ePseudo_PseudoElementCount || + CSSPseudoElementType pseudo = selector->PseudoType(); + if (pseudo >= CSSPseudoElementType::Count || !nsCSSPseudoElements::PseudoElementSupportsUserActionState(pseudo)) { NS_ASSERTION(!selector->mNegations, "Shouldn't have negations"); // We do store selectors ending with pseudo-elements that allow :hover diff --git a/layout/style/nsCSSRuleProcessor.h b/layout/style/nsCSSRuleProcessor.h index 38b4094939af..8dc1e21d1d23 100644 --- a/layout/style/nsCSSRuleProcessor.h +++ b/layout/style/nsCSSRuleProcessor.h @@ -19,7 +19,6 @@ #include "mozilla/SheetType.h" #include "mozilla/UniquePtr.h" #include "nsAutoPtr.h" -#include "nsCSSPseudoElements.h" #include "nsExpirationTracker.h" #include "nsIMediaList.h" #include "nsIStyleRuleProcessor.h" @@ -40,6 +39,7 @@ class nsCSSCounterStyleRule; namespace mozilla { class CSSStyleSheet; +enum class CSSPseudoElementType : uint8_t; namespace css { class DocumentRule; } // namespace css @@ -234,7 +234,7 @@ private: nsRestyleHint HasStateDependentStyle(ElementDependentRuleProcessorData* aData, mozilla::dom::Element* aStatefulElement, - nsCSSPseudoElements::Type aPseudoType, + mozilla::CSSPseudoElementType aPseudoType, mozilla::EventStates aStateMask); void ClearSheets(); diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp index b8680fe23e59..21b0d5f46fa3 100644 --- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -488,8 +488,8 @@ nsComputedDOMStyle::GetStyleContextForElementNoFlush(Element* aElement, RefPtr sc; if (aPseudo) { - nsCSSPseudoElements::Type type = nsCSSPseudoElements::GetPseudoType(aPseudo); - if (type >= nsCSSPseudoElements::ePseudo_PseudoElementCount) { + CSSPseudoElementType type = nsCSSPseudoElements::GetPseudoType(aPseudo); + if (type >= CSSPseudoElementType::Count) { return nullptr; } nsIFrame* frame = nsLayoutUtils::GetStyleFrame(aElement); @@ -696,8 +696,7 @@ nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush) while (topWithPseudoElementData->GetParent()->HasPseudoElementData()) { topWithPseudoElementData = topWithPseudoElementData->GetParent(); } - nsCSSPseudoElements::Type pseudo = - topWithPseudoElementData->GetPseudoType(); + CSSPseudoElementType pseudo = topWithPseudoElementData->GetPseudoType(); nsIAtom* pseudoAtom = nsCSSPseudoElements::GetPseudoAtom(pseudo); nsAutoString assertMsg( NS_LITERAL_STRING("we should be in a pseudo-element that is expected to contain elements (")); diff --git a/layout/style/nsDOMCSSAttrDeclaration.cpp b/layout/style/nsDOMCSSAttrDeclaration.cpp index 9462f2344892..7b9ba2a870dc 100644 --- a/layout/style/nsDOMCSSAttrDeclaration.cpp +++ b/layout/style/nsDOMCSSAttrDeclaration.cpp @@ -186,7 +186,7 @@ nsDOMCSSAttributeDeclaration::SetPropertyValue(const nsCSSProperty aPropID, aPropID == eCSSProperty_background_position) { nsIFrame* frame = mElement->GetPrimaryFrame(); if (frame) { - ActiveLayerTracker::NotifyInlineStyleRuleModified(frame, aPropID); + ActiveLayerTracker::NotifyInlineStyleRuleModified(frame, aPropID, aValue, this); } } return nsDOMCSSDeclaration::SetPropertyValue(aPropID, aValue); diff --git a/layout/style/nsHTMLCSSStyleSheet.cpp b/layout/style/nsHTMLCSSStyleSheet.cpp index 51dd7db55fd9..f6b2ae54908f 100644 --- a/layout/style/nsHTMLCSSStyleSheet.cpp +++ b/layout/style/nsHTMLCSSStyleSheet.cpp @@ -18,6 +18,7 @@ #include "mozilla/dom/Element.h" #include "nsAttrValue.h" #include "nsAttrValueInlines.h" +#include "nsCSSPseudoElements.h" #include "RestyleManager.h" using namespace mozilla; @@ -81,7 +82,7 @@ nsHTMLCSSStyleSheet::ElementRulesMatching(nsPresContext* aPresContext, void nsHTMLCSSStyleSheet::PseudoElementRulesMatching(Element* aPseudoElement, - nsCSSPseudoElements::Type + CSSPseudoElementType aPseudoType, nsRuleWalker* aRuleWalker) { diff --git a/layout/style/nsHTMLCSSStyleSheet.h b/layout/style/nsHTMLCSSStyleSheet.h index b8fdc4c81303..2b7ea7ae8322 100644 --- a/layout/style/nsHTMLCSSStyleSheet.h +++ b/layout/style/nsHTMLCSSStyleSheet.h @@ -13,7 +13,6 @@ #include "mozilla/Attributes.h" #include "mozilla/MemoryReporting.h" -#include "nsCSSPseudoElements.h" #include "nsDataHashtable.h" #include "nsIStyleRuleProcessor.h" @@ -21,6 +20,7 @@ class nsRuleWalker; struct MiscContainer; namespace mozilla { +enum class CSSPseudoElementType : uint8_t; namespace dom { class Element; } // namespace dom @@ -60,7 +60,7 @@ public: // aPseudoElement here is the content node for the pseudo-element, not // its corresponding real element. void PseudoElementRulesMatching(mozilla::dom::Element* aPseudoElement, - nsCSSPseudoElements::Type aPseudoType, + mozilla::CSSPseudoElementType aPseudoType, nsRuleWalker* aRuleWalker); void CacheStyleAttr(const nsAString& aSerialized, MiscContainer* aValue); diff --git a/layout/style/nsRuleProcessorData.h b/layout/style/nsRuleProcessorData.h index 3deefbc6f265..3373cb9f1d2d 100644 --- a/layout/style/nsRuleProcessorData.h +++ b/layout/style/nsRuleProcessorData.h @@ -470,7 +470,7 @@ struct MOZ_STACK_CLASS PseudoElementRuleProcessorData : PseudoElementRuleProcessorData(nsPresContext* aPresContext, mozilla::dom::Element* aParentElement, nsRuleWalker* aRuleWalker, - nsCSSPseudoElements::Type aPseudoType, + mozilla::CSSPseudoElementType aPseudoType, TreeMatchContext& aTreeMatchContext, mozilla::dom::Element* aPseudoElement) : ElementDependentRuleProcessorData(aPresContext, aParentElement, aRuleWalker, @@ -478,14 +478,13 @@ struct MOZ_STACK_CLASS PseudoElementRuleProcessorData : mPseudoType(aPseudoType), mPseudoElement(aPseudoElement) { - NS_PRECONDITION(aPseudoType < - nsCSSPseudoElements::ePseudo_PseudoElementCount, + NS_PRECONDITION(aPseudoType < mozilla::CSSPseudoElementType::Count, "invalid aPseudoType value"); NS_PRECONDITION(aTreeMatchContext.mForStyling, "Styling here!"); NS_PRECONDITION(aRuleWalker, "Must have rule walker"); } - nsCSSPseudoElements::Type mPseudoType; + mozilla::CSSPseudoElementType mPseudoType; mozilla::dom::Element* const mPseudoElement; // weak ref }; @@ -550,7 +549,7 @@ struct MOZ_STACK_CLASS PseudoElementStateRuleProcessorData : PseudoElementStateRuleProcessorData(nsPresContext* aPresContext, mozilla::dom::Element* aElement, mozilla::EventStates aStateMask, - nsCSSPseudoElements::Type aPseudoType, + mozilla::CSSPseudoElementType aPseudoType, TreeMatchContext& aTreeMatchContext, mozilla::dom::Element* aPseudoElement) : StateRuleProcessorData(aPresContext, aElement, aStateMask, @@ -564,7 +563,7 @@ struct MOZ_STACK_CLASS PseudoElementStateRuleProcessorData : // We kind of want to inherit from both StateRuleProcessorData and // PseudoElementRuleProcessorData. Instead we've just copied those // members from PseudoElementRuleProcessorData to this struct. - nsCSSPseudoElements::Type mPseudoType; + mozilla::CSSPseudoElementType mPseudoType; mozilla::dom::Element* const mPseudoElement; // weak ref }; diff --git a/layout/style/nsStyleContext.cpp b/layout/style/nsStyleContext.cpp index 95afde7f6044..90c58c69c6f8 100644 --- a/layout/style/nsStyleContext.cpp +++ b/layout/style/nsStyleContext.cpp @@ -2,13 +2,14 @@ /* 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/. */ - + /* the interface (to internal code) for retrieving computed style data */ #include "CSSVariableImageTable.h" #include "mozilla/DebugOnly.h" #include "nsCSSAnonBoxes.h" +#include "nsCSSPseudoElements.h" #include "nsStyleConsts.h" #include "nsString.h" #include "nsPresContext.h" @@ -70,7 +71,7 @@ static bool sExpensiveStyleStructAssertionsEnabled; nsStyleContext::nsStyleContext(nsStyleContext* aParent, nsIAtom* aPseudoTag, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, nsRuleNode* aRuleNode, bool aSkipParentDisplayBasedStyleFixup) : mParent(aParent) @@ -89,7 +90,7 @@ nsStyleContext::nsStyleContext(nsStyleContext* aParent, // This check has to be done "backward", because if it were written the // more natural way it wouldn't fail even when it needed to. static_assert((UINT64_MAX >> NS_STYLE_CONTEXT_TYPE_SHIFT) >= - nsCSSPseudoElements::ePseudo_MAX, + static_cast(CSSPseudoElementType::MAX), "pseudo element bits no longer fit in a uint64_t"); MOZ_ASSERT(aRuleNode); @@ -526,7 +527,7 @@ ShouldSuppressLineBreak(const nsStyleContext* aContext, // some other frame with a ruby display value. Non-element pseudos // which represents text frames, as well as ruby pseudos are excluded // because we still want to set the flag for them. - if (aContext->GetPseudoType() == nsCSSPseudoElements::ePseudo_AnonBox && + if (aContext->GetPseudoType() == CSSPseudoElementType::AnonBox && aContext->GetPseudo() != nsCSSAnonBoxes::mozNonElement && !RubyUtils::IsRubyPseudo(aContext->GetPseudo())) { return false; @@ -1216,7 +1217,7 @@ nsStyleContext::Destroy() already_AddRefed NS_NewStyleContext(nsStyleContext* aParentContext, nsIAtom* aPseudoTag, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, nsRuleNode* aRuleNode, bool aSkipParentDisplayBasedStyleFixup) { diff --git a/layout/style/nsStyleContext.h b/layout/style/nsStyleContext.h index 7e0a1f119601..edd9e9518f65 100644 --- a/layout/style/nsStyleContext.h +++ b/layout/style/nsStyleContext.h @@ -11,11 +11,14 @@ #include "mozilla/RestyleLogging.h" #include "mozilla/Assertions.h" #include "nsRuleNode.h" -#include "nsCSSPseudoElements.h" class nsIAtom; class nsPresContext; +namespace mozilla { +enum class CSSPseudoElementType : uint8_t; +} // namespace mozilla + /** * An nsStyleContext represents the computed style data for an element. * The computed style data are stored in a set of structs (see @@ -60,13 +63,13 @@ public: * matches. See |nsRuleNode| and |nsIStyleRule|. * @param aSkipParentDisplayBasedStyleFixup * If set, this flag indicates that we should skip - * the chunk of ApplyStyleFixups() that applies to - * special cases where a child element's style may - * need to be modified based on its parent's display + * the chunk of ApplyStyleFixups() that applies to + * special cases where a child element's style may + * need to be modified based on its parent's display * value. */ nsStyleContext(nsStyleContext* aParent, nsIAtom* aPseudoTag, - nsCSSPseudoElements::Type aPseudoType, + mozilla::CSSPseudoElementType aPseudoType, nsRuleNode* aRuleNode, bool aSkipParentDisplayBasedStyleFixup); @@ -137,9 +140,9 @@ public: nsStyleContext* GetParent() const { return mParent; } nsIAtom* GetPseudo() const { return mPseudoTag; } - nsCSSPseudoElements::Type GetPseudoType() const { - return static_cast(mBits >> - NS_STYLE_CONTEXT_TYPE_SHIFT); + mozilla::CSSPseudoElementType GetPseudoType() const { + return static_cast( + mBits >> NS_STYLE_CONTEXT_TYPE_SHIFT); } // Find, if it already exists *and is easily findable* (i.e., near the @@ -629,7 +632,7 @@ private: already_AddRefed NS_NewStyleContext(nsStyleContext* aParentContext, nsIAtom* aPseudoTag, - nsCSSPseudoElements::Type aPseudoType, + mozilla::CSSPseudoElementType aPseudoType, nsRuleNode* aRuleNode, bool aSkipParentDisplayBasedStyleFixup); #endif diff --git a/layout/style/nsStyleSet.cpp b/layout/style/nsStyleSet.cpp index d7c600716429..f7e706af1555 100644 --- a/layout/style/nsStyleSet.cpp +++ b/layout/style/nsStyleSet.cpp @@ -885,13 +885,13 @@ nsStyleSet::GetContext(nsStyleContext* aParentContext, // should be used.) nsRuleNode* aVisitedRuleNode, nsIAtom* aPseudoTag, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, Element* aElementForAnimation, uint32_t aFlags) { NS_PRECONDITION((!aPseudoTag && aPseudoType == - nsCSSPseudoElements::ePseudo_NotPseudoElement) || + CSSPseudoElementType::NotPseudo) || (aPseudoTag && nsCSSPseudoElements::GetPseudoType(aPseudoTag) == aPseudoType), @@ -1016,7 +1016,7 @@ nsStyleSet::GetContext(nsStyleContext* aParentContext, if (aElementForAnimation && aElementForAnimation->IsHTMLElement(nsGkAtoms::body) && - aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement && + aPseudoType == CSSPseudoElementType::NotPseudo && PresContext()->CompatibilityMode() == eCompatibility_NavQuirks) { nsIDocument* doc = aElementForAnimation->GetCurrentDoc(); if (doc && doc->GetBodyElement() == aElementForAnimation) { @@ -1395,7 +1395,7 @@ nsStyleSet::ResolveStyleFor(Element* aElement, } return GetContext(aParentContext, ruleNode, visitedRuleNode, - nullptr, nsCSSPseudoElements::ePseudo_NotPseudoElement, + nullptr, CSSPseudoElementType::NotPseudo, aElement, flags); } @@ -1414,7 +1414,7 @@ nsStyleSet::ResolveStyleForRules(nsStyleContext* aParentContext, } return GetContext(aParentContext, ruleWalker.CurrentNode(), nullptr, - nullptr, nsCSSPseudoElements::ePseudo_NotPseudoElement, + nullptr, CSSPseudoElementType::NotPseudo, nullptr, eNoFlags); } @@ -1504,13 +1504,13 @@ nsRuleNode* nsStyleSet::RuleNodeWithReplacement(Element* aElement, Element* aPseudoElement, nsRuleNode* aOldRuleNode, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, nsRestyleHint aReplacements) { NS_ASSERTION(mBatching == 0, "rule processors out of date"); MOZ_ASSERT(!aPseudoElement == - (aPseudoType >= nsCSSPseudoElements::ePseudo_PseudoElementCount || + (aPseudoType >= CSSPseudoElementType::Count || !(nsCSSPseudoElements::PseudoElementSupportsStyleAttribute(aPseudoType) || nsCSSPseudoElements::PseudoElementSupportsUserActionState(aPseudoType))), "should have aPseudoElement only for certain pseudo elements"); @@ -1565,9 +1565,9 @@ nsStyleSet::RuleNodeWithReplacement(Element* aElement, if (doReplace) { switch (level->mLevel) { case SheetType::Animation: { - if (aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement || - aPseudoType == nsCSSPseudoElements::ePseudo_before || - aPseudoType == nsCSSPseudoElements::ePseudo_after) { + if (aPseudoType == CSSPseudoElementType::NotPseudo || + aPseudoType == CSSPseudoElementType::before || + aPseudoType == CSSPseudoElementType::after) { nsIStyleRule* rule = PresContext()->EffectCompositor()-> GetAnimationRule(aElement, aPseudoType, EffectCompositor::CascadeLevel::Animations); @@ -1579,9 +1579,9 @@ nsStyleSet::RuleNodeWithReplacement(Element* aElement, break; } case SheetType::Transition: { - if (aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement || - aPseudoType == nsCSSPseudoElements::ePseudo_before || - aPseudoType == nsCSSPseudoElements::ePseudo_after) { + if (aPseudoType == CSSPseudoElementType::NotPseudo || + aPseudoType == CSSPseudoElementType::before || + aPseudoType == CSSPseudoElementType::after) { nsIStyleRule* rule = PresContext()->EffectCompositor()-> GetAnimationRule(aElement, aPseudoType, EffectCompositor::CascadeLevel::Transitions); @@ -1597,7 +1597,7 @@ nsStyleSet::RuleNodeWithReplacement(Element* aElement, static_cast( mRuleProcessors[SheetType::SVGAttrAnimation].get()); if (ruleProcessor && - aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) { + aPseudoType == CSSPseudoElementType::NotPseudo) { ruleProcessor->ElementRulesMatching(aElement, &ruleWalker); } break; @@ -1611,12 +1611,12 @@ nsStyleSet::RuleNodeWithReplacement(Element* aElement, if (ruleProcessor) { lastScopedRN = ruleWalker.CurrentNode(); if (aPseudoType == - nsCSSPseudoElements::ePseudo_NotPseudoElement) { + CSSPseudoElementType::NotPseudo) { ruleProcessor->ElementRulesMatching(PresContext(), aElement, &ruleWalker); } else if (aPseudoType < - nsCSSPseudoElements::ePseudo_PseudoElementCount && + CSSPseudoElementType::Count && nsCSSPseudoElements:: PseudoElementSupportsStyleAttribute(aPseudoType)) { ruleProcessor->PseudoElementRulesMatching(aPseudoElement, @@ -1706,12 +1706,12 @@ nsStyleSet::ResolveStyleWithReplacement(Element* aElement, } } - nsCSSPseudoElements::Type pseudoType = aOldStyleContext->GetPseudoType(); + CSSPseudoElementType pseudoType = aOldStyleContext->GetPseudoType(); Element* elementForAnimation = nullptr; if (!(aFlags & eSkipStartingAnimations) && - (pseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement || - pseudoType == nsCSSPseudoElements::ePseudo_before || - pseudoType == nsCSSPseudoElements::ePseudo_after)) { + (pseudoType == CSSPseudoElementType::NotPseudo || + pseudoType == CSSPseudoElementType::before || + pseudoType == CSSPseudoElementType::after)) { // We want to compute a correct elementForAnimation to pass in // because at this point the parameter is more than just the element // for animation; it's also used for the SetBodyTextColor call when @@ -1728,11 +1728,10 @@ nsStyleSet::ResolveStyleWithReplacement(Element* aElement, #ifdef DEBUG { nsIFrame* styleFrame = nsLayoutUtils::GetStyleFrame(elementForAnimation); - NS_ASSERTION(pseudoType == - nsCSSPseudoElements::ePseudo_NotPseudoElement || + NS_ASSERTION(pseudoType == CSSPseudoElementType::NotPseudo || !styleFrame || styleFrame->StyleContext()->GetPseudoType() == - nsCSSPseudoElements::ePseudo_NotPseudoElement, + CSSPseudoElementType::NotPseudo, "aElement should be the element and not the pseudo-element"); } #endif @@ -1757,11 +1756,11 @@ nsStyleSet::ResolveStyleWithoutAnimation(dom::Element* aTarget, nsRestyleHint aWhichToRemove) { #ifdef DEBUG - nsCSSPseudoElements::Type pseudoType = aStyleContext->GetPseudoType(); + CSSPseudoElementType pseudoType = aStyleContext->GetPseudoType(); #endif - MOZ_ASSERT(pseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement || - pseudoType == nsCSSPseudoElements::ePseudo_before || - pseudoType == nsCSSPseudoElements::ePseudo_after, + MOZ_ASSERT(pseudoType == CSSPseudoElementType::NotPseudo || + pseudoType == CSSPseudoElementType::before || + pseudoType == CSSPseudoElementType::after, "unexpected type for animations"); RestyleManager* restyleManager = PresContext()->RestyleManager(); @@ -1783,21 +1782,21 @@ nsStyleSet::ResolveStyleForNonElement(nsStyleContext* aParentContext) { return GetContext(aParentContext, mRuleTree, nullptr, nsCSSAnonBoxes::mozNonElement, - nsCSSPseudoElements::ePseudo_AnonBox, nullptr, + CSSPseudoElementType::AnonBox, nullptr, eNoFlags); } void -nsStyleSet::WalkRestrictionRule(nsCSSPseudoElements::Type aPseudoType, +nsStyleSet::WalkRestrictionRule(CSSPseudoElementType aPseudoType, nsRuleWalker* aRuleWalker) { // This needs to match GetPseudoRestriction in nsRuleNode.cpp. aRuleWalker->SetLevel(SheetType::Agent, false, false); - if (aPseudoType == nsCSSPseudoElements::ePseudo_firstLetter) + if (aPseudoType == CSSPseudoElementType::firstLetter) aRuleWalker->Forward(mFirstLetterRule); - else if (aPseudoType == nsCSSPseudoElements::ePseudo_firstLine) + else if (aPseudoType == CSSPseudoElementType::firstLine) aRuleWalker->Forward(mFirstLineRule); - else if (aPseudoType == nsCSSPseudoElements::ePseudo_mozPlaceholder) + else if (aPseudoType == CSSPseudoElementType::mozPlaceholder) aRuleWalker->Forward(mPlaceholderRule); } @@ -1811,13 +1810,13 @@ nsStyleSet::WalkDisableTextZoomRule(Element* aElement, nsRuleWalker* aRuleWalker already_AddRefed nsStyleSet::ResolvePseudoElementStyle(Element* aParentElement, - nsCSSPseudoElements::Type aType, + CSSPseudoElementType aType, nsStyleContext* aParentContext, Element* aPseudoElement) { NS_ENSURE_FALSE(mInShutdown, nullptr); - NS_ASSERTION(aType < nsCSSPseudoElements::ePseudo_PseudoElementCount, + NS_ASSERTION(aType < CSSPseudoElementType::Count, "must have pseudo element type"); NS_ASSERTION(aParentElement, "Must have parent element"); @@ -1847,8 +1846,8 @@ nsStyleSet::ResolvePseudoElementStyle(Element* aParentElement, // For pseudos, |data.IsLink()| being true means that // our parent node is a link. uint32_t flags = eNoFlags; - if (aType == nsCSSPseudoElements::ePseudo_before || - aType == nsCSSPseudoElements::ePseudo_after) { + if (aType == CSSPseudoElementType::before || + aType == CSSPseudoElementType::after) { flags |= eDoAnimation; } else { // Flex and grid containers don't expect to have any pseudo-element children @@ -1865,7 +1864,7 @@ nsStyleSet::ResolvePseudoElementStyle(Element* aParentElement, already_AddRefed nsStyleSet::ProbePseudoElementStyle(Element* aParentElement, - nsCSSPseudoElements::Type aType, + CSSPseudoElementType aType, nsStyleContext* aParentContext) { TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited, @@ -1877,14 +1876,14 @@ nsStyleSet::ProbePseudoElementStyle(Element* aParentElement, already_AddRefed nsStyleSet::ProbePseudoElementStyle(Element* aParentElement, - nsCSSPseudoElements::Type aType, + CSSPseudoElementType aType, nsStyleContext* aParentContext, TreeMatchContext& aTreeMatchContext, Element* aPseudoElement) { NS_ENSURE_FALSE(mInShutdown, nullptr); - NS_ASSERTION(aType < nsCSSPseudoElements::ePseudo_PseudoElementCount, + NS_ASSERTION(aType < CSSPseudoElementType::Count, "must have pseudo element type"); NS_ASSERTION(aParentElement, "aParentElement must not be null"); @@ -1919,8 +1918,8 @@ nsStyleSet::ProbePseudoElementStyle(Element* aParentElement, // For pseudos, |data.IsLink()| being true means that // our parent node is a link. uint32_t flags = eNoFlags; - if (aType == nsCSSPseudoElements::ePseudo_before || - aType == nsCSSPseudoElements::ePseudo_after) { + if (aType == CSSPseudoElementType::before || + aType == CSSPseudoElementType::after) { flags |= eDoAnimation; } else { // Flex and grid containers don't expect to have any pseudo-element children @@ -1995,7 +1994,7 @@ nsStyleSet::ResolveAnonymousBoxStyle(nsIAtom* aPseudoTag, } return GetContext(aParentContext, ruleWalker.CurrentNode(), nullptr, - aPseudoTag, nsCSSPseudoElements::ePseudo_AnonBox, + aPseudoTag, CSSPseudoElementType::AnonBox, nullptr, aFlags); } @@ -2035,7 +2034,7 @@ nsStyleSet::ResolveXULTreePseudoStyle(Element* aParentElement, return GetContext(aParentContext, ruleNode, visitedRuleNode, // For pseudos, |data.IsLink()| being true means that // our parent node is a link. - aPseudoTag, nsCSSPseudoElements::ePseudo_XULTree, + aPseudoTag, CSSPseudoElementType::XULTree, nullptr, eNoFlags); } #endif @@ -2266,7 +2265,7 @@ nsStyleSet::ReparentStyleContext(nsStyleContext* aStyleContext, } nsIAtom* pseudoTag = aStyleContext->GetPseudo(); - nsCSSPseudoElements::Type pseudoType = aStyleContext->GetPseudoType(); + CSSPseudoElementType pseudoType = aStyleContext->GetPseudoType(); nsRuleNode* ruleNode = aStyleContext->RuleNode(); NS_ASSERTION(!PresContext()->RestyleManager()->SkipAnimationRules(), @@ -2294,9 +2293,9 @@ nsStyleSet::ReparentStyleContext(nsStyleContext* aStyleContext, } } - if (pseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement || - pseudoType == nsCSSPseudoElements::ePseudo_before || - pseudoType == nsCSSPseudoElements::ePseudo_after) { + if (pseudoType == CSSPseudoElementType::NotPseudo || + pseudoType == CSSPseudoElementType::before || + pseudoType == CSSPseudoElementType::after) { flags |= eDoAnimation; } @@ -2325,7 +2324,7 @@ struct MOZ_STACK_CLASS StatefulData : public StateRuleProcessorData { struct MOZ_STACK_CLASS StatefulPseudoElementData : public PseudoElementStateRuleProcessorData { StatefulPseudoElementData(nsPresContext* aPresContext, Element* aElement, - EventStates aStateMask, nsCSSPseudoElements::Type aPseudoType, + EventStates aStateMask, CSSPseudoElementType aPseudoType, TreeMatchContext& aTreeMatchContext, Element* aPseudoElement) : PseudoElementStateRuleProcessorData(aPresContext, aElement, aStateMask, aPseudoType, aTreeMatchContext, @@ -2396,7 +2395,7 @@ nsStyleSet::HasStateDependentStyle(Element* aElement, nsRestyleHint nsStyleSet::HasStateDependentStyle(Element* aElement, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, Element* aPseudoElement, EventStates aStateMask) { diff --git a/layout/style/nsStyleSet.h b/layout/style/nsStyleSet.h index 2af75dc1abfb..a05bcf210d06 100644 --- a/layout/style/nsStyleSet.h +++ b/layout/style/nsStyleSet.h @@ -25,7 +25,6 @@ #include "nsCOMArray.h" #include "nsAutoPtr.h" #include "nsIStyleRule.h" -#include "nsCSSPseudoElements.h" class gfxFontFeatureValueSet; class nsCSSKeyframesRule; @@ -41,6 +40,7 @@ struct TreeMatchContext; namespace mozilla { class CSSStyleSheet; class EventStates; +enum class CSSPseudoElementType : uint8_t; } // namespace mozilla class nsEmptyStyleRule final : public nsIStyleRule @@ -172,13 +172,13 @@ class nsStyleSet final ResolveStyleForNonElement(nsStyleContext* aParentContext); // Get a style context for a pseudo-element. aParentElement must be - // non-null. aPseudoID is the nsCSSPseudoElements::Type for the + // non-null. aPseudoID is the CSSPseudoElementType for the // pseudo-element. aPseudoElement must be non-null if the pseudo-element // type is one that allows user action pseudo-classes after it or allows // style attributes; otherwise, it is ignored. already_AddRefed ResolvePseudoElementStyle(mozilla::dom::Element* aParentElement, - nsCSSPseudoElements::Type aType, + mozilla::CSSPseudoElementType aType, nsStyleContext* aParentContext, mozilla::dom::Element* aPseudoElement); @@ -187,11 +187,11 @@ class nsStyleSet final // pseudo element. already_AddRefed ProbePseudoElementStyle(mozilla::dom::Element* aParentElement, - nsCSSPseudoElements::Type aType, + mozilla::CSSPseudoElementType aType, nsStyleContext* aParentContext); already_AddRefed ProbePseudoElementStyle(mozilla::dom::Element* aParentElement, - nsCSSPseudoElements::Type aType, + mozilla::CSSPseudoElementType aType, nsStyleContext* aParentContext, TreeMatchContext& aTreeMatchContext, mozilla::dom::Element* aPseudoElement = nullptr); @@ -283,7 +283,7 @@ class nsStyleSet final nsRestyleHint HasStateDependentStyle(mozilla::dom::Element* aElement, mozilla::EventStates aStateMask); nsRestyleHint HasStateDependentStyle(mozilla::dom::Element* aElement, - nsCSSPseudoElements::Type aPseudoType, + mozilla::CSSPseudoElementType aPseudoType, mozilla::dom::Element* aPseudoElement, mozilla::EventStates aStateMask); @@ -419,7 +419,7 @@ private: // Move aRuleWalker forward by the appropriate rule if we need to add // a rule due to property restrictions on pseudo-elements. - void WalkRestrictionRule(nsCSSPseudoElements::Type aPseudoType, + void WalkRestrictionRule(mozilla::CSSPseudoElementType aPseudoType, nsRuleWalker* aRuleWalker); void WalkDisableTextZoomRule(mozilla::dom::Element* aElement, @@ -460,7 +460,7 @@ private: nsRuleNode* RuleNodeWithReplacement(mozilla::dom::Element* aElement, mozilla::dom::Element* aPseudoElement, nsRuleNode* aOldRuleNode, - nsCSSPseudoElements::Type aPseudoType, + mozilla::CSSPseudoElementType aPseudoType, nsRestyleHint aReplacements); already_AddRefed @@ -468,7 +468,7 @@ private: nsRuleNode* aRuleNode, nsRuleNode* aVisitedRuleNode, nsIAtom* aPseudoTag, - nsCSSPseudoElements::Type aPseudoType, + mozilla::CSSPseudoElementType aPseudoType, mozilla::dom::Element* aElementForAnimation, uint32_t aFlags); diff --git a/layout/style/nsTransitionManager.cpp b/layout/style/nsTransitionManager.cpp index 483796b81ea9..4ea84fbca763 100644 --- a/layout/style/nsTransitionManager.cpp +++ b/layout/style/nsTransitionManager.cpp @@ -28,6 +28,7 @@ #include "Layers.h" #include "FrameLayerBuilder.h" #include "nsCSSProps.h" +#include "nsCSSPseudoElements.h" #include "nsDisplayList.h" #include "nsStyleChangeList.h" #include "nsStyleSet.h" @@ -129,7 +130,7 @@ CSSTransition::QueueEvents() } dom::Element* owningElement; - nsCSSPseudoElements::Type owningPseudoType; + CSSPseudoElementType owningPseudoType; mOwningElement.GetElement(owningElement, owningPseudoType); MOZ_ASSERT(owningElement, "Owning element should be set"); @@ -261,16 +262,16 @@ nsTransitionManager::StyleContextChanged(dom::Element *aElement, // Return sooner (before the startedAny check below) for the most // common case: no transitions specified or running. const nsStyleDisplay *disp = newStyleContext->StyleDisplay(); - nsCSSPseudoElements::Type pseudoType = newStyleContext->GetPseudoType(); - if (pseudoType != nsCSSPseudoElements::ePseudo_NotPseudoElement) { - if (pseudoType != nsCSSPseudoElements::ePseudo_before && - pseudoType != nsCSSPseudoElements::ePseudo_after) { + CSSPseudoElementType pseudoType = newStyleContext->GetPseudoType(); + if (pseudoType != CSSPseudoElementType::NotPseudo) { + if (pseudoType != CSSPseudoElementType::before && + pseudoType != CSSPseudoElementType::after) { return; } - NS_ASSERTION((pseudoType == nsCSSPseudoElements::ePseudo_before && + NS_ASSERTION((pseudoType == CSSPseudoElementType::before && aElement->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentbefore) || - (pseudoType == nsCSSPseudoElements::ePseudo_after && + (pseudoType == CSSPseudoElementType::after && aElement->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentafter), "Unexpected aElement coming through"); @@ -734,8 +735,7 @@ nsTransitionManager::ConsiderStartingTransition( void nsTransitionManager::PruneCompletedTransitions(mozilla::dom::Element* aElement, - nsCSSPseudoElements::Type - aPseudoType, + CSSPseudoElementType aPseudoType, nsStyleContext* aNewStyleContext) { AnimationCollection* collection = diff --git a/layout/style/nsTransitionManager.h b/layout/style/nsTransitionManager.h index 35c627af82b2..a4c35f46b463 100644 --- a/layout/style/nsTransitionManager.h +++ b/layout/style/nsTransitionManager.h @@ -16,7 +16,6 @@ #include "mozilla/dom/KeyframeEffect.h" #include "AnimationCommon.h" #include "nsCSSProps.h" -#include "nsCSSPseudoElements.h" class nsIGlobalObject; class nsStyleContext; @@ -24,6 +23,7 @@ class nsPresContext; class nsCSSPropertySet; namespace mozilla { +enum class CSSPseudoElementType : uint8_t; struct StyleTransition; } // namespace mozilla @@ -37,7 +37,7 @@ struct ElementPropertyTransition : public dom::KeyframeEffectReadOnly { ElementPropertyTransition(nsIDocument* aDocument, dom::Element* aTarget, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, const TimingParams &aTiming, StyleAnimationValue aStartForReversingTest, double aReversePortion) @@ -216,7 +216,7 @@ struct TransitionEventInfo { TimeStamp mTimeStamp; TransitionEventInfo(dom::Element* aElement, - nsCSSPseudoElements::Type aPseudoType, + CSSPseudoElementType aPseudoType, nsCSSProperty aProperty, StickyTimeDuration aDuration, const TimeStamp& aTimeStamp, @@ -289,7 +289,7 @@ public: * new style. */ void PruneCompletedTransitions(mozilla::dom::Element* aElement, - nsCSSPseudoElements::Type aPseudoType, + mozilla::CSSPseudoElementType aPseudoType, nsStyleContext* aNewStyleContext); void SetInAnimationOnlyStyleUpdate(bool aInAnimationOnlyUpdate) { diff --git a/layout/style/xbl-marquee/xbl-marquee.xml b/layout/style/xbl-marquee/xbl-marquee.xml index 4951553fe3b4..1b5b71a256ef 100644 --- a/layout/style/xbl-marquee/xbl-marquee.xml +++ b/layout/style/xbl-marquee/xbl-marquee.xml @@ -20,6 +20,7 @@ + this._mutationActor(this._mutationObserver.takeRecords()); return this._behavior; @@ -90,6 +93,7 @@ + + + + 0) { + var mutation = aMutations.shift(); + var attrName = mutation.attributeName.toLowerCase(); + var oldValue = mutation.oldValue; + var target = mutation.target; + var newValue = target.getAttribute(attrName); + + if (oldValue != newValue) { + switch (attrName) { + case "loop": + if (!target._set_loop(newValue)) { + if (!newValue) { + target._loop = -1; + if (target.runId == 0) + target.start(); + } + } + if (target.rundId == 0) + target.start(); + break; + case "scrollamount": + if (!newValue) + target._scrollAmount = 6; + else + target._set_scrollAmount(newValue); + break; + case "scrolldelay": + if (!newValue) + target._scrollDelay = 85; + else + target._set_scrollDelay(newValue); + target.stop(); + target.start(); + break; + case "truespeed": + //needed to update target._scrollDelay + var myThis = target; + var lambda = function() {myThis._set_scrollDelay(myThis.getAttribute('scrolldelay'));} + window.setTimeout(lambda, 0); + break; + case "behavior": + if (!newValue) + target._behavior = "scroll"; + else + target._set_behavior(newValue); + target.startNewDirection = true; + if ((oldValue == "slide" && target.newPosition == target.stopAt) || + newValue == "alternate" || newValue == "slide") { + target.stop(); + target._doMove(true); + } + break; + case "direction": + if (!newValue) + target._direction = "left"; + else + target._set_direction(newValue); + break; + case "width": + case "height": + target.startNewDirection = true; + break; + case "onstart": + target._setEventListener("start", newValue); + break; + case "onfinish": + target._setEventListener("finish", newValue); + break; + case "onbounce": + target._setEventListener("bounce", newValue); + break; + } + } + } + ]]> + + + - - - - - - & Codecs() = 0; + template + void ForEachCodec(UnaryFunction& function) + { + std::for_each(Codecs().begin(), Codecs().end(), function); + for (RefPtr& track : GetLocalTracks()) { + track->ForEachCodec(function); + } + for (RefPtr& track : GetRemoteTracks()) { + track->ForEachCodec(function); + } + } + + template + void SortCodecs(BinaryPredicate& sorter) + { + std::stable_sort(Codecs().begin(), Codecs().end(), sorter); + for (RefPtr& track : GetLocalTracks()) { + track->SortCodecs(sorter); + } + for (RefPtr& track : GetRemoteTracks()) { + track->SortCodecs(sorter); + } + } + // Manage tracks. We take shared ownership of any track. virtual nsresult AddTrack(const RefPtr& track) = 0; virtual nsresult RemoveTrack(const std::string& streamId, diff --git a/media/webrtc/signaling/src/jsep/JsepTrack.h b/media/webrtc/signaling/src/jsep/JsepTrack.h index 519acf2cbcb5..70feb80f8370 100644 --- a/media/webrtc/signaling/src/jsep/JsepTrack.h +++ b/media/webrtc/signaling/src/jsep/JsepTrack.h @@ -5,6 +5,7 @@ #ifndef _JSEPTRACK_H_ #define _JSEPTRACK_H_ +#include #include #include #include @@ -138,6 +139,21 @@ public: virtual void PopulateCodecs( const std::vector& prototype); + + template + void ForEachCodec(UnaryFunction& func) + { + std::for_each(mPrototypeCodecs.values.begin(), + mPrototypeCodecs.values.end(), func); + } + + template + void SortCodecs(BinaryPredicate& sorter) + { + std::stable_sort(mPrototypeCodecs.values.begin(), + mPrototypeCodecs.values.end(), sorter); + } + virtual void AddToOffer(SdpMediaSection* offer) const; virtual void AddToAnswer(const SdpMediaSection& offer, SdpMediaSection* answer) const; diff --git a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp index 1fec411cf971..c18abf83a1d4 100644 --- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp +++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp @@ -995,7 +995,7 @@ void MediaPipelineTransmit::PipelineListener::ProcessAudioChunk( // input audio is either mono or stereo). uint32_t outputChannels = chunk.ChannelCount() == 1 ? 1 : 2; const int16_t* samples = nullptr; - nsAutoArrayPtr convertedSamples; + UniquePtr convertedSamples; // If this track is not enabled, simply ignore the data in the chunk. if (!enabled_) { @@ -1009,7 +1009,7 @@ void MediaPipelineTransmit::PipelineListener::ProcessAudioChunk( if (outputChannels == 1 && chunk.mBufferFormat == AUDIO_FORMAT_S16) { samples = chunk.ChannelData().Elements()[0]; } else { - convertedSamples = new int16_t[chunk.mDuration * outputChannels]; + convertedSamples = MakeUnique(chunk.mDuration * outputChannels); switch (chunk.mBufferFormat) { case AUDIO_FORMAT_FLOAT32: @@ -1084,16 +1084,15 @@ void MediaPipelineTransmit::PipelineListener::ProcessVideoChunk( uint32_t length = yPlaneLen + cbcrPlaneLen; // Send a black image. - nsAutoArrayPtr pixelData; - pixelData = new (fallible) uint8_t[length]; + auto pixelData = MakeUniqueFallible(length); if (pixelData) { // YCrCb black = 0x10 0x80 0x80 - memset(pixelData, 0x10, yPlaneLen); + memset(pixelData.get(), 0x10, yPlaneLen); // Fill Cb/Cr planes - memset(pixelData + yPlaneLen, 0x80, cbcrPlaneLen); + memset(pixelData.get() + yPlaneLen, 0x80, cbcrPlaneLen); MOZ_MTLOG(ML_DEBUG, "Sending a black video frame"); - conduit->SendVideoFrame(pixelData, length, size.width, size.height, + conduit->SendVideoFrame(pixelData.get(), length, size.width, size.height, mozilla::kVideoI420, 0); } return; diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp index 533a65a70399..c79b830d0783 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp @@ -973,13 +973,158 @@ class CompareCodecPriority { std::string mPreferredCodec; }; +#if !defined(MOZILLA_XPCOMRT_API) +class ConfigureCodec { + public: + explicit ConfigureCodec(nsCOMPtr& branch) : + mHardwareH264Enabled(false), + mHardwareH264Supported(false), + mSoftwareH264Enabled(false), + mH264Enabled(false), + mVP9Enabled(false), + mH264Level(13), // minimum suggested for WebRTC spec + mH264MaxBr(0), // Unlimited + mH264MaxMbps(0), // Unlimited + mVP8MaxFs(0), + mVP8MaxFr(0), + mUseTmmbr(false) + { +#ifdef MOZ_WEBRTC_OMX + // Check to see if what HW codecs are available (not in use) at this moment. + // Note that streaming video decode can reserve a decoder + + // XXX See bug 1018791 Implement W3 codec reservation policy + // Note that currently, OMXCodecReservation needs to be held by an sp<> because it puts + // 'this' into an sp to talk to the resource reservation code + + // This pref is a misnomer; it is solely for h264 _hardware_ support. + branch->GetBoolPref("media.peerconnection.video.h264_enabled", + &mHardwareH264Enabled); + + if (mHardwareH264Enabled) { + // Ok, it is preffed on. Can we actually do it? + android::sp encode = new android::OMXCodecReservation(true); + android::sp decode = new android::OMXCodecReservation(false); + + // Currently we just check if they're available right now, which will fail if we're + // trying to call ourself, for example. It will work for most real-world cases, like + // if we try to add a person to a 2-way call to make a 3-way mesh call + if (encode->ReserveOMXCodec() && decode->ReserveOMXCodec()) { + CSFLogDebug( logTag, "%s: H264 hardware codec available", __FUNCTION__); + mHardwareH264Supported = true; + } + } + +#endif // MOZ_WEBRTC_OMX + +#if !defined(MOZILLA_EXTERNAL_LINKAGE) + mSoftwareH264Enabled = PeerConnectionCtx::GetInstance()->gmpHasH264(); +#else + // For unit-tests + mSoftwareH264Enabled = true; +#endif + + mH264Enabled = mHardwareH264Supported || mSoftwareH264Enabled; + + branch->GetIntPref("media.navigator.video.h264.level", &mH264Level); + mH264Level &= 0xFF; + + branch->GetIntPref("media.navigator.video.h264.max_br", &mH264MaxBr); + +#ifdef MOZ_WEBRTC_OMX + // Level 1.2; but let's allow CIF@30 or QVGA@30+ by default + mH264MaxMbps = 11880; +#endif + + branch->GetIntPref("media.navigator.video.h264.max_mbps", &mH264MaxMbps); + + branch->GetBoolPref("media.peerconnection.video.vp9_enabled", + &mVP9Enabled); + + branch->GetIntPref("media.navigator.video.max_fs", &mVP8MaxFs); + if (mVP8MaxFs <= 0) { + mVP8MaxFs = 12288; // We must specify something other than 0 + } + + branch->GetIntPref("media.navigator.video.max_fr", &mVP8MaxFr); + if (mVP8MaxFr <= 0) { + mVP8MaxFr = 60; // We must specify something other than 0 + } + + // TMMBR is enabled from a pref in about:config + branch->GetBoolPref("media.navigator.video.use_tmmbr", &mUseTmmbr); + } + + void operator()(JsepCodecDescription* codec) const + { + switch (codec->mType) { + case SdpMediaSection::kAudio: + // Nothing to configure here, for now. + break; + case SdpMediaSection::kVideo: + { + JsepVideoCodecDescription& videoCodec = + static_cast(*codec); + + if (videoCodec.mName == "H264") { + // Override level + videoCodec.mProfileLevelId &= 0xFFFF00; + videoCodec.mProfileLevelId |= mH264Level; + + videoCodec.mConstraints.maxBr = mH264MaxBr; + + videoCodec.mConstraints.maxMbps = mH264MaxMbps; + + // Might disable it, but we set up other params anyway + videoCodec.mEnabled = mH264Enabled; + + if (videoCodec.mPacketizationMode == 0 && !mSoftwareH264Enabled) { + // We're assuming packetization mode 0 is unsupported by + // hardware. + videoCodec.mEnabled = false; + } + + if (mHardwareH264Supported) { + videoCodec.mStronglyPreferred = true; + } + } else if (videoCodec.mName == "VP8" || videoCodec.mName == "VP9") { + if (videoCodec.mName == "VP9" && !mVP9Enabled) { + videoCodec.mEnabled = false; + break; + } + videoCodec.mConstraints.maxFs = mVP8MaxFs; + videoCodec.mConstraints.maxFps = mVP8MaxFr; + } + + if (mUseTmmbr) { + videoCodec.EnableTmmbr(); + } + } + break; + case SdpMediaSection::kText: + case SdpMediaSection::kApplication: + case SdpMediaSection::kMessage: + {} // Nothing to configure for these. + } + } + + private: + bool mHardwareH264Enabled; + bool mHardwareH264Supported; + bool mSoftwareH264Enabled; + bool mH264Enabled; + bool mVP9Enabled; + int32_t mH264Level; + int32_t mH264MaxBr; + int32_t mH264MaxMbps; + int32_t mVP8MaxFs; + int32_t mVP8MaxFr; + bool mUseTmmbr; +}; +#endif // !defined(MOZILLA_XPCOMRT_API) + nsresult PeerConnectionImpl::ConfigureJsepSessionCodecs() { - if (mHaveConfiguredCodecs) { - return NS_OK; - } - mHaveConfiguredCodecs = true; - #if !defined(MOZILLA_XPCOMRT_API) nsresult res; nsCOMPtr prefs = @@ -987,8 +1132,8 @@ PeerConnectionImpl::ConfigureJsepSessionCodecs() { if (NS_FAILED(res)) { CSFLogError(logTag, "%s: Couldn't get prefs service, res=%u", - __FUNCTION__, - static_cast(res)); + __FUNCTION__, + static_cast(res)); return res; } @@ -998,138 +1143,12 @@ PeerConnectionImpl::ConfigureJsepSessionCodecs() { return NS_ERROR_FAILURE; } - - bool hardwareH264Supported = false; - -#ifdef MOZ_WEBRTC_OMX - bool hardwareH264Enabled = false; - - // Check to see if what HW codecs are available (not in use) at this moment. - // Note that streaming video decode can reserve a decoder - - // XXX See bug 1018791 Implement W3 codec reservation policy - // Note that currently, OMXCodecReservation needs to be held by an sp<> because it puts - // 'this' into an sp to talk to the resource reservation code - - // This pref is a misnomer; it is solely for h264 _hardware_ support. - branch->GetBoolPref("media.peerconnection.video.h264_enabled", - &hardwareH264Enabled); - - if (hardwareH264Enabled) { - // Ok, it is preffed on. Can we actually do it? - android::sp encode = new android::OMXCodecReservation(true); - android::sp decode = new android::OMXCodecReservation(false); - - // Currently we just check if they're available right now, which will fail if we're - // trying to call ourself, for example. It will work for most real-world cases, like - // if we try to add a person to a 2-way call to make a 3-way mesh call - if (encode->ReserveOMXCodec() && decode->ReserveOMXCodec()) { - CSFLogDebug( logTag, "%s: H264 hardware codec available", __FUNCTION__); - hardwareH264Supported = true; - } - } - -#endif // MOZ_WEBRTC_OMX - -#if !defined(MOZILLA_EXTERNAL_LINKAGE) - bool softwareH264Enabled = PeerConnectionCtx::GetInstance()->gmpHasH264(); -#else - // For unit-tests - bool softwareH264Enabled = true; -#endif - - bool h264Enabled = hardwareH264Supported || softwareH264Enabled; - - bool vp9Enabled = false; - branch->GetBoolPref("media.peerconnection.video.vp9_enabled", - &vp9Enabled); - - auto& codecs = mJsepSession->Codecs(); + ConfigureCodec configurer(branch); + mJsepSession->ForEachCodec(configurer); // We use this to sort the list of codecs once everything is configured CompareCodecPriority comparator; - // Set parameters - for (auto i = codecs.begin(); i != codecs.end(); ++i) { - auto &codec = **i; - switch (codec.mType) { - case SdpMediaSection::kAudio: - // Nothing to configure here, for now. - break; - case SdpMediaSection::kVideo: - { - JsepVideoCodecDescription& videoCodec = - static_cast(codec); - - if (videoCodec.mName == "H264") { - int32_t level = 13; // minimum suggested for WebRTC spec - branch->GetIntPref("media.navigator.video.h264.level", &level); - level &= 0xFF; - // Override level - videoCodec.mProfileLevelId &= 0xFFFF00; - videoCodec.mProfileLevelId |= level; - - int32_t maxBr = 0; // Unlimited - branch->GetIntPref("media.navigator.video.h264.max_br", &maxBr); - videoCodec.mConstraints.maxBr = maxBr; - - int32_t maxMbps = 0; // Unlimited -#ifdef MOZ_WEBRTC_OMX - // Level 1.2; but let's allow CIF@30 or QVGA@30+ by default - maxMbps = 11880; -#endif - branch->GetIntPref("media.navigator.video.h264.max_mbps", &maxMbps); - videoCodec.mConstraints.maxMbps = maxMbps; - - // Might disable it, but we set up other params anyway - videoCodec.mEnabled = h264Enabled; - - if (videoCodec.mPacketizationMode == 0 && !softwareH264Enabled) { - // We're assuming packetization mode 0 is unsupported by - // hardware. - videoCodec.mEnabled = false; - } - - if (hardwareH264Supported) { - videoCodec.mStronglyPreferred = true; - } - } else if (codec.mName == "VP8" || codec.mName == "VP9") { - if (videoCodec.mName == "VP9" && !vp9Enabled) { - videoCodec.mEnabled = false; - break; - } - int32_t maxFs = 0; - branch->GetIntPref("media.navigator.video.max_fs", &maxFs); - if (maxFs <= 0) { - maxFs = 12288; // We must specify something other than 0 - } - videoCodec.mConstraints.maxFs = maxFs; - - int32_t maxFr = 0; - branch->GetIntPref("media.navigator.video.max_fr", &maxFr); - if (maxFr <= 0) { - maxFr = 60; // We must specify something other than 0 - } - videoCodec.mConstraints.maxFps = maxFr; - - } - - // TMMBR is enabled from a pref in about:config - bool useTmmbr = false; - branch->GetBoolPref("media.navigator.video.use_tmmbr", - &useTmmbr); - if (useTmmbr) { - videoCodec.EnableTmmbr(); - } - } - break; - case SdpMediaSection::kText: - case SdpMediaSection::kApplication: - case SdpMediaSection::kMessage: - {} // Nothing to configure for these. - } - } - // Sort by priority int32_t preferredCodec = 0; branch->GetIntPref("media.navigator.video.preferred_codec", @@ -1139,7 +1158,7 @@ PeerConnectionImpl::ConfigureJsepSessionCodecs() { comparator.SetPreferredCodec(preferredCodec); } - std::stable_sort(codecs.begin(), codecs.end(), comparator); + mJsepSession->SortCodecs(comparator); #endif // !defined(MOZILLA_XPCOMRT_API) return NS_OK; } @@ -1260,17 +1279,6 @@ PeerConnectionImpl::AddTrackToJsepSession(SdpMediaSection::MediaType type, const std::string& streamId, const std::string& trackId) { - if (!PeerConnectionCtx::GetInstance()->isReady()) { - // We are not ready to configure codecs for this track. We need to defer. - PeerConnectionCtx::GetInstance()->queueJSEPOperation( - WrapRunnableNM(DeferredAddTrackToJsepSession, - mHandle, - type, - streamId, - trackId)); - return NS_OK; - } - nsresult res = ConfigureJsepSessionCodecs(); if (NS_FAILED(res)) { CSFLogError(logTag, "Failed to configure codecs"); diff --git a/media/webrtc/signaling/test/sdp_unittests.cpp b/media/webrtc/signaling/test/sdp_unittests.cpp index fc4e58970c94..51eb6c0ff344 100644 --- a/media/webrtc/signaling/test/sdp_unittests.cpp +++ b/media/webrtc/signaling/test/sdp_unittests.cpp @@ -2825,16 +2825,16 @@ TEST(NewSdpTestNoFixture, CheckImageattrXYRangeParseInvalid) { ParseInvalid("[-1", 1); ParseInvalid("[-", 1); - ParseInvalid("[-x", 1); + ParseInvalid("[-v", 1); ParseInvalid("[640:-1", 5); ParseInvalid("[640:16:-1", 8); ParseInvalid("[640,-1", 5); ParseInvalid("[640,-]", 5); - ParseInvalid("-x", 0); + ParseInvalid("-v", 0); ParseInvalid("-1", 0); ParseInvalid("", 0); ParseInvalid("[", 1); - ParseInvalid("[x", 1); + ParseInvalid("[v", 1); ParseInvalid("[", 1); ParseInvalid("[ 640", 1); // It looks like the overflow detection only happens once the whole number @@ -2842,23 +2842,23 @@ TEST(NewSdpTestNoFixture, CheckImageattrXYRangeParseInvalid) ParseInvalid("[99999999999999999:", 18); ParseInvalid("[640", 4); ParseInvalid("[640:", 5); - ParseInvalid("[640:x", 5); + ParseInvalid("[640:v", 5); ParseInvalid("[640:16", 7); ParseInvalid("[640:16:", 8); - ParseInvalid("[640:16:x", 8); + ParseInvalid("[640:16:v", 8); ParseInvalid("[640:16:320]", 11); ParseInvalid("[640:16:320", 11); - ParseInvalid("[640:16:320x", 11); + ParseInvalid("[640:16:320v", 11); ParseInvalid("[640:1024", 9); ParseInvalid("[640:320]", 8); - ParseInvalid("[640:1024x", 9); + ParseInvalid("[640:1024v", 9); ParseInvalid("[640,", 5); - ParseInvalid("[640,x", 5); + ParseInvalid("[640,v", 5); ParseInvalid("[640]", 4); ParseInvalid("[640x", 4); ParseInvalid("[640,]", 5); ParseInvalid(" ", 0); - ParseInvalid("x", 0); + ParseInvalid("v", 0); } static SdpImageattrAttributeList::SRange @@ -2908,31 +2908,31 @@ TEST(NewSdpTestNoFixture, CheckImageattrSRangeParseInvalid) { ParseInvalid("", 0); ParseInvalid("[", 1); - ParseInvalid("[x", 1); + ParseInvalid("[v", 1); ParseInvalid("[-1", 1); ParseInvalid("[", 1); ParseInvalid("[-", 1); - ParseInvalid("[x", 1); + ParseInvalid("[v", 1); ParseInvalid("[ 0.2", 1); ParseInvalid("[10.1-", 5); ParseInvalid("[0.08-", 5); ParseInvalid("[0.2", 4); ParseInvalid("[0.2-", 5); - ParseInvalid("[0.2-x", 5); + ParseInvalid("[0.2-v", 5); ParseInvalid("[0.2--1", 5); ParseInvalid("[0.2-0.3", 8); ParseInvalid("[0.2-0.1]", 8); - ParseInvalid("[0.2-0.3x", 8); + ParseInvalid("[0.2-0.3v", 8); ParseInvalid("[0.2,", 5); - ParseInvalid("[0.2,x", 5); + ParseInvalid("[0.2,v", 5); ParseInvalid("[0.2,-1", 5); ParseInvalid("[0.2]", 4); - ParseInvalid("[0.2x", 4); + ParseInvalid("[0.2v", 4); ParseInvalid("[0.2,]", 5); ParseInvalid("[0.2,-]", 5); ParseInvalid(" ", 0); - ParseInvalid("x", 0); - ParseInvalid("-x", 0); + ParseInvalid("v", 0); + ParseInvalid("-v", 0); ParseInvalid("-1", 0); } @@ -2959,27 +2959,27 @@ TEST(NewSdpTestNoFixture, CheckImageattrPRangeParseInvalid) { ParseInvalid("", 0); ParseInvalid("[", 1); - ParseInvalid("[x", 1); + ParseInvalid("[v", 1); ParseInvalid("[-1", 1); ParseInvalid("[", 1); ParseInvalid("[-", 1); - ParseInvalid("[x", 1); + ParseInvalid("[v", 1); ParseInvalid("[ 0.2", 1); ParseInvalid("[10.1-", 5); ParseInvalid("[0.08-", 5); ParseInvalid("[0.2", 4); ParseInvalid("[0.2-", 5); - ParseInvalid("[0.2-x", 5); + ParseInvalid("[0.2-v", 5); ParseInvalid("[0.2--1", 5); ParseInvalid("[0.2-0.3", 8); ParseInvalid("[0.2-0.1]", 8); - ParseInvalid("[0.2-0.3x", 8); + ParseInvalid("[0.2-0.3v", 8); ParseInvalid("[0.2,", 4); ParseInvalid("[0.2:", 4); ParseInvalid("[0.2]", 4); - ParseInvalid("[0.2x", 4); + ParseInvalid("[0.2v", 4); ParseInvalid(" ", 0); - ParseInvalid("x", 0); + ParseInvalid("v", 0); ParseInvalid("-x", 0); ParseInvalid("-1", 0); } @@ -3131,7 +3131,7 @@ TEST(NewSdpTestNoFixture, CheckImageattrSetParseInvalid) ParseInvalid("[y=", 3); ParseInvalid("[x=[", 4); ParseInvalid("[x=320", 6); - ParseInvalid("[x=320x", 6); + ParseInvalid("[x=320v", 6); ParseInvalid("[x=320,", 7); ParseInvalid("[x=320,=", 8); ParseInvalid("[x=320,x", 8); @@ -3141,15 +3141,15 @@ TEST(NewSdpTestNoFixture, CheckImageattrSetParseInvalid) ParseInvalid("[x=320,y=240x", 12); ParseInvalid("[x=320,y=240,", 13); ParseInvalid("[x=320,y=240,q=", 15); - ParseInvalid("[x=320,y=240,q=x", 15); + ParseInvalid("[x=320,y=240,q=v", 15); ParseInvalid("[x=320,y=240,q=0.5", 18); ParseInvalid("[x=320,y=240,q=0.5,", 19); ParseInvalid("[x=320,y=240,q=0.5,]", 20); ParseInvalid("[x=320,y=240,q=0.5,=]", 20); - ParseInvalid("[x=320,y=240,q=0.5,sar=x]", 23); + ParseInvalid("[x=320,y=240,q=0.5,sar=v]", 23); ParseInvalid("[x=320,y=240,q=0.5,q=0.4", 21); ParseInvalid("[x=320,y=240,sar=", 17); - ParseInvalid("[x=320,y=240,sar=x", 17); + ParseInvalid("[x=320,y=240,sar=v", 17); ParseInvalid( "[x=320,y=240,sar=[0.5-0.6],sar=[0.7-0.8]", 31); ParseInvalid("[x=320,y=240,par=", 17); diff --git a/media/webrtc/trunk/webrtc/system_wrappers/source/trace_impl.cc b/media/webrtc/trunk/webrtc/system_wrappers/source/trace_impl.cc index 4322603412d7..af6b3d5739db 100644 --- a/media/webrtc/trunk/webrtc/system_wrappers/source/trace_impl.cc +++ b/media/webrtc/trunk/webrtc/system_wrappers/source/trace_impl.cc @@ -353,27 +353,26 @@ int32_t TraceImpl::AddMessage( if (written_so_far >= WEBRTC_TRACE_MAX_MESSAGE_SIZE) { return -1; } - // - 2 to leave room for newline and NULL termination. + // - 1 to leave room for newline. #ifdef _WIN32 length = _snprintf(trace_message, - WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2, - "%s", msg); + WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 1, + "%s\n", msg); if (length < 0) { - length = WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2; + length = WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 1; trace_message[length] = 0; } #else length = snprintf(trace_message, - WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2, - "%s", msg); + WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 1, + "%s\n", msg); if (length < 0 || - length > WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2) { - length = WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2; + length > WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 1) { + length = WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 1; trace_message[length] = 0; } #endif - // Length with NULL termination. - return length + 1; + return length; } void TraceImpl::AddMessageToList( diff --git a/mobile/android/base/java/org/mozilla/gecko/toolbar/BrowserToolbar.java b/mobile/android/base/java/org/mozilla/gecko/toolbar/BrowserToolbar.java index 2fdbfaba850b..9a2d26f6bd20 100644 --- a/mobile/android/base/java/org/mozilla/gecko/toolbar/BrowserToolbar.java +++ b/mobile/android/base/java/org/mozilla/gecko/toolbar/BrowserToolbar.java @@ -56,6 +56,7 @@ import android.view.inputmethod.InputMethodManager; import android.widget.Button; import android.widget.LinearLayout; import android.widget.PopupWindow; +import android.support.annotation.NonNull; /** * {@code BrowserToolbar} is single entry point for users of the toolbar @@ -402,7 +403,7 @@ public abstract class BrowserToolbar extends ThemedRelativeLayout } @Override - public void onTabChanged(Tab tab, Tabs.TabEvents msg, Object data) { + public void onTabChanged(@NonNull Tab tab, Tabs.TabEvents msg, Object data) { Log.d(LOGTAG, "onTabChanged: " + msg); final Tabs tabs = Tabs.getInstance(); @@ -591,7 +592,7 @@ public abstract class BrowserToolbar extends ThemedRelativeLayout activity.getString(R.string.one_tab)); } - private void updateDisplayLayout(Tab tab, EnumSet flags) { + private void updateDisplayLayout(@NonNull Tab tab, EnumSet flags) { if (isSwitchingTabs) { flags.add(UpdateFlags.DISABLE_ANIMATIONS); } diff --git a/mobile/android/base/java/org/mozilla/gecko/toolbar/ToolbarDisplayLayout.java b/mobile/android/base/java/org/mozilla/gecko/toolbar/ToolbarDisplayLayout.java index 6d554353ab84..efd4dab1dc4e 100644 --- a/mobile/android/base/java/org/mozilla/gecko/toolbar/ToolbarDisplayLayout.java +++ b/mobile/android/base/java/org/mozilla/gecko/toolbar/ToolbarDisplayLayout.java @@ -29,6 +29,7 @@ import org.mozilla.gecko.widget.themed.ThemedTextView; import android.content.Context; import android.os.SystemClock; import android.support.annotation.Nullable; +import android.support.annotation.NonNull; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.TextUtils; @@ -190,7 +191,7 @@ public class ToolbarDisplayLayout extends ThemedLinearLayout { mPrefs = prefs; } - void updateFromTab(Tab tab, EnumSet flags) { + void updateFromTab(@NonNull Tab tab, EnumSet flags) { // Several parts of ToolbarDisplayLayout's state depends // on the views being attached to the view tree. if (!mIsAttached) { @@ -210,7 +211,7 @@ public class ToolbarDisplayLayout extends ThemedLinearLayout { } if (flags.contains(UpdateFlags.PRIVATE_MODE)) { - mTitle.setPrivateMode(tab != null && tab.isPrivate()); + mTitle.setPrivateMode(tab.isPrivate()); } } @@ -222,10 +223,10 @@ public class ToolbarDisplayLayout extends ThemedLinearLayout { } } - private void updateTitle(Tab tab) { + private void updateTitle(@NonNull Tab tab) { // Keep the title unchanged if there's no selected tab, // or if the tab is entering reader mode. - if (tab == null || tab.isEnteringReaderMode()) { + if (tab.isEnteringReaderMode()) { return; } @@ -279,13 +280,8 @@ public class ToolbarDisplayLayout extends ThemedLinearLayout { return ReaderModeUtils.getUrlFromAboutReader(url); } - private void updateSiteIdentity(Tab tab) { - final SiteIdentity siteIdentity; - if (tab == null) { - siteIdentity = null; - } else { - siteIdentity = tab.getSiteIdentity(); - } + private void updateSiteIdentity(@NonNull Tab tab) { + final SiteIdentity siteIdentity = tab.getSiteIdentity(); mSiteIdentityPopup.setSiteIdentity(siteIdentity); @@ -342,13 +338,12 @@ public class ToolbarDisplayLayout extends ThemedLinearLayout { mTrackingProtectionEnabled = trackingMode == TrackingMode.TRACKING_CONTENT_BLOCKED; } - private void updateProgress(@Nullable Tab tab) { - final boolean shouldShowThrobber = (tab != null && - tab.getState() == Tab.STATE_LOADING); + private void updateProgress(@NonNull Tab tab) { + final boolean shouldShowThrobber = tab.getState() == Tab.STATE_LOADING; updateUiMode(shouldShowThrobber ? UIMode.PROGRESS : UIMode.DISPLAY); - if (tab != null && Tab.STATE_SUCCESS == tab.getState() && mTrackingProtectionEnabled) { + if (Tab.STATE_SUCCESS == tab.getState() && mTrackingProtectionEnabled) { mActivity.showTrackingProtectionPromptIfApplicable(); } } diff --git a/mozglue/build/Nuwa.cpp b/mozglue/build/Nuwa.cpp index 42d9bad34a39..4be83e699609 100644 --- a/mozglue/build/Nuwa.cpp +++ b/mozglue/build/Nuwa.cpp @@ -2077,7 +2077,7 @@ IsNuwaReady() { return sNuwaReady; } -#if defined(DEBUG) || defined(ENABLE_TESTS) +#if defined(DEBUG) MFBT_API void NuwaAssertNotFrozen(unsigned int aThread, const char* aThreadName) { if (!sIsNuwaProcess || !sIsFreezing) { diff --git a/mozglue/build/Nuwa.h b/mozglue/build/Nuwa.h index 37c8baebf603..13d71ebfef02 100644 --- a/mozglue/build/Nuwa.h +++ b/mozglue/build/Nuwa.h @@ -187,7 +187,7 @@ MFBT_API bool IsNuwaProcess(); */ MFBT_API bool IsNuwaReady(); -#if defined(DEBUG) || defined(ENABLE_TESTS) +#if defined(DEBUG) /** * Asserts that aThread is not frozen. */ diff --git a/netwerk/base/PollableEvent.cpp b/netwerk/base/PollableEvent.cpp new file mode 100644 index 000000000000..825977bd5c99 --- /dev/null +++ b/netwerk/base/PollableEvent.cpp @@ -0,0 +1,163 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsSocketTransportService2.h" +#include "PollableEvent.h" +#include "mozilla/Assertions.h" +#include "mozilla/DebugOnly.h" +#include "mozilla/Logging.h" +#include "prerror.h" +#include "prio.h" +#include "private/pprio.h" + +#ifdef XP_WIN +#include "ShutdownLayer.h" +#else +#include +#define USEPIPE 1 +#endif + +namespace mozilla { +namespace net { + +PollableEvent::PollableEvent() + : mWriteFD(nullptr) + , mReadFD(nullptr) + , mSignaled(false) +{ + // create pair of prfiledesc that can be used as a poll()ble + // signal. on windows use a localhost socket pair, and on + // unix use a pipe. +#ifdef USEPIPE + if (PR_CreatePipe(&mReadFD, &mWriteFD) == PR_SUCCESS) { + // make the pipe non blocking. NSPR asserts at + // trying to use SockOpt here + PROsfd fd = PR_FileDesc2NativeHandle(mReadFD); + int flags = fcntl(fd, F_GETFL, 0); + (void)fcntl(fd, F_SETFL, flags | O_NONBLOCK); + fd = PR_FileDesc2NativeHandle(mWriteFD); + flags = fcntl(fd, F_GETFL, 0); + (void)fcntl(fd, F_SETFL, flags | O_NONBLOCK); + } else { + mReadFD = nullptr; + mWriteFD = nullptr; + SOCKET_LOG(("PollableEvent() pipe failed\n")); + } +#else + PRFileDesc *fd[2]; + if (PR_NewTCPSocketPair(fd) == PR_SUCCESS) { + mReadFD = fd[0]; + mWriteFD = fd[1]; + + PRSocketOptionData opt; + DebugOnly status; + opt.option = PR_SockOpt_NoDelay; + opt.value.no_delay = true; + PR_SetSocketOption(mWriteFD, &opt); + PR_SetSocketOption(mReadFD, &opt); + opt.option = PR_SockOpt_Nonblocking; + opt.value.non_blocking = true; + status = PR_SetSocketOption(mWriteFD, &opt); + MOZ_ASSERT(status == PR_SUCCESS); + status = PR_SetSocketOption(mReadFD, &opt); + MOZ_ASSERT(status == PR_SUCCESS); + } else { + SOCKET_LOG(("PollableEvent() socketpair failed\n")); + } +#endif + + if (mReadFD && mWriteFD) { + // prime the system to deal with races invovled in [dc]tor cycle + SOCKET_LOG(("PollableEvent() ctor ok\n")); + mSignaled = true; + PR_Write(mWriteFD, "I", 1); + } +} + +PollableEvent::~PollableEvent() +{ + if (mWriteFD) { +#if defined(XP_WIN) + mozilla::net::AttachShutdownLayer(mWriteFD); +#endif + PR_Close(mWriteFD); + } + if (mReadFD) { +#if defined(XP_WIN) + mozilla::net::AttachShutdownLayer(mReadFD); +#endif + PR_Close(mReadFD); + } +} + +// we do not record signals on the socket thread +// because the socket thread can reliably look at its +// own runnable queue before selecting a poll time +// this is the "service the network without blocking" comment in +// nsSocketTransportService2.cpp +bool +PollableEvent::Signal() +{ + SOCKET_LOG(("PollableEvent::Signal\n")); + + if (!mWriteFD) { + SOCKET_LOG(("PollableEvent::Signal Failed on no FD\n")); + return false; + } + if (PR_GetCurrentThread() == gSocketThread) { + SOCKET_LOG(("PollableEvent::Signal OnSocketThread nop\n")); + return true; + } + if (mSignaled) { + return true; + } + mSignaled = true; + int32_t status = PR_Write(mWriteFD, "M", 1); + if (status != 1) { + NS_WARNING("PollableEvent::Signal Failed\n"); + SOCKET_LOG(("PollableEvent::Signal Failed\n")); + } + return (status == 1); +} + +bool +PollableEvent::Clear() +{ + // necessary because of the "dont signal on socket thread" optimization + MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); + + SOCKET_LOG(("PollableEvent::Clear\n")); + mSignaled = false; + if (!mReadFD) { + SOCKET_LOG(("PollableEvent::Clear mReadFD is null\n")); + return false; + } + char buf[2048]; + int32_t status = PR_Read(mReadFD, buf, 2048); + + if (status == 1) { + return true; + } + if (status == 0) { + SOCKET_LOG(("PollableEvent::Clear EOF!\n")); + return false; + } + if (status > 1) { + MOZ_ASSERT(false); + SOCKET_LOG(("PollableEvent::Clear Unexpected events\n")); + Clear(); + return true; + } + PRErrorCode code = PR_GetError(); + if (code == PR_WOULD_BLOCK_ERROR) { + return true; + } + SOCKET_LOG(("PollableEvent::Clear unexpected error %d\n", code)); + return false; +} + +} // namespace net +} // namespace mozilla diff --git a/netwerk/base/PollableEvent.h b/netwerk/base/PollableEvent.h new file mode 100644 index 000000000000..80007993200d --- /dev/null +++ b/netwerk/base/PollableEvent.h @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef PollableEvent_h__ +#define PollableEvent_h__ + +#include "mozilla/Mutex.h" + +namespace mozilla { +namespace net { + +// class must be called locked +class PollableEvent +{ +public: + PollableEvent(); + ~PollableEvent(); + + // Signal/Clear return false only if they fail + bool Signal(); + bool Clear(); + bool Valid() { return mWriteFD && mReadFD; } + + PRFileDesc *PollableFD() { return mReadFD; } + +private: + PRFileDesc *mWriteFD; + PRFileDesc *mReadFD; + bool mSignaled; +}; + +} // namespace net +} // namespace mozilla + +#endif diff --git a/netwerk/base/SimpleBuffer.cpp b/netwerk/base/SimpleBuffer.cpp new file mode 100644 index 000000000000..d0e311f77cdf --- /dev/null +++ b/netwerk/base/SimpleBuffer.cpp @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SimpleBuffer.h" +#include + +namespace mozilla { +namespace net { + +SimpleBuffer::SimpleBuffer() + : mStatus(NS_OK) + , mAvailable(0) +{ + mOwningThread = PR_GetCurrentThread(); +} + +nsresult SimpleBuffer::Write(char *src, size_t len) +{ + MOZ_ASSERT(PR_GetCurrentThread() == mOwningThread); + if (NS_FAILED(mStatus)) { + return mStatus; + } + + while (len > 0) { + SimpleBufferPage *p = mBufferList.getLast(); + if (p && (p->mWriteOffset == SimpleBufferPage::kSimpleBufferPageSize)) { + // no room.. make a new page + p = nullptr; + } + if (!p) { + p = new (fallible) SimpleBufferPage(); + if (!p) { + mStatus = NS_ERROR_OUT_OF_MEMORY; + return mStatus; + } + mBufferList.insertBack(p); + } + size_t roomOnPage = SimpleBufferPage::kSimpleBufferPageSize - p->mWriteOffset; + size_t toWrite = std::min(roomOnPage, len); + memcpy(p->mBuffer + p->mWriteOffset, src, toWrite); + src += toWrite; + len -= toWrite; + p->mWriteOffset += toWrite; + mAvailable += toWrite; + } + return NS_OK; +} + +size_t SimpleBuffer::Read(char *dest, size_t maxLen) +{ + MOZ_ASSERT(PR_GetCurrentThread() == mOwningThread); + if (NS_FAILED(mStatus)) { + return 0; + } + + size_t rv = 0; + for (SimpleBufferPage *p = mBufferList.getFirst(); + p && (rv < maxLen); p = mBufferList.getFirst()) { + size_t avail = p->mWriteOffset - p->mReadOffset; + size_t toRead = std::min(avail, (maxLen - rv)); + memcpy(dest + rv, p->mBuffer + p->mReadOffset, toRead); + rv += toRead; + p->mReadOffset += toRead; + if (p->mReadOffset == p->mWriteOffset) { + p->remove(); + delete p; + } + } + + MOZ_ASSERT(mAvailable >= rv); + mAvailable -= rv; + return rv; +} + +size_t SimpleBuffer::Available() +{ + MOZ_ASSERT(PR_GetCurrentThread() == mOwningThread); + return NS_SUCCEEDED(mStatus) ? mAvailable : 0; +} + +void SimpleBuffer::Clear() +{ + MOZ_ASSERT(PR_GetCurrentThread() == mOwningThread); + SimpleBufferPage *p; + while ((p = mBufferList.popFirst())) { + delete p; + } + mAvailable = 0; +} + +} // namespace net +} // namespace mozilla diff --git a/netwerk/base/SimpleBuffer.h b/netwerk/base/SimpleBuffer.h new file mode 100644 index 000000000000..765239001319 --- /dev/null +++ b/netwerk/base/SimpleBuffer.h @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef SimpleBuffer_h__ +#define SimpleBuffer_h__ + +/* + This class is similar to a nsPipe except it does not have any locking, stores + an unbounded amount of data, can only be used on one thread, and has much + simpler result code semantics to deal with. +*/ + +#include "prtypes.h" +#include "mozilla/LinkedList.h" +#include "nsIThreadInternal.h" + +namespace mozilla { +namespace net { + +class SimpleBufferPage : public LinkedListElement +{ +public: + SimpleBufferPage() : mReadOffset(0), mWriteOffset(0) {} + static const size_t kSimpleBufferPageSize = 32000; + +private: + friend class SimpleBuffer; + char mBuffer[kSimpleBufferPageSize]; + size_t mReadOffset; + size_t mWriteOffset; +}; + +class SimpleBuffer +{ +public: + SimpleBuffer(); + ~SimpleBuffer() {} + + nsresult Write(char *stc, size_t len); // return OK or OUT_OF_MEMORY + size_t Read(char *dest, size_t maxLen); // return bytes read + size_t Available(); + void Clear(); + +private: + PRThread *mOwningThread; + nsresult mStatus; + AutoCleanLinkedList mBufferList; + size_t mAvailable; +}; + +} // namespace net +} // namespace mozilla + +#endif diff --git a/netwerk/base/moz.build b/netwerk/base/moz.build index 3426159ddae9..21bec45a3a74 100644 --- a/netwerk/base/moz.build +++ b/netwerk/base/moz.build @@ -249,10 +249,12 @@ UNIFIED_SOURCES += [ 'nsURLHelper.cpp', 'nsURLParsers.cpp', 'OfflineObserver.cpp', + 'PollableEvent.cpp', 'Predictor.cpp', 'ProxyAutoConfig.cpp', 'RedirectChannelRegistrar.cpp', 'SchedulingContextService.cpp', + 'SimpleBuffer.cpp', 'StreamingProtocolService.cpp', 'Tickler.cpp', 'TLSServerSocket.cpp', diff --git a/netwerk/base/nsIOService.cpp b/netwerk/base/nsIOService.cpp index e72ebafe374c..2e519f7dcc4d 100644 --- a/netwerk/base/nsIOService.cpp +++ b/netwerk/base/nsIOService.cpp @@ -1021,9 +1021,6 @@ nsIOService::SetOffline(bool offline) NS_IOSERVICE_GOING_OFFLINE_TOPIC, offlineString.get()); - if (mDNSService) - mDNSService->SetOffline(true); - if (mSocketTransportService) mSocketTransportService->SetOffline(true); @@ -1036,7 +1033,6 @@ nsIOService::SetOffline(bool offline) else if (!offline && mOffline) { // go online if (mDNSService) { - mDNSService->SetOffline(false); DebugOnly rv = mDNSService->Init(); NS_ASSERTION(NS_SUCCEEDED(rv), "DNS service init failed"); } diff --git a/netwerk/base/nsSocketTransportService2.cpp b/netwerk/base/nsSocketTransportService2.cpp index 6f036616fbf0..17f9ee39fa91 100644 --- a/netwerk/base/nsSocketTransportService2.cpp +++ b/netwerk/base/nsSocketTransportService2.cpp @@ -89,13 +89,13 @@ DebugMutexAutoLock::~DebugMutexAutoLock() nsSocketTransportService::nsSocketTransportService() : mThread(nullptr) - , mThreadEvent(nullptr) , mAutodialEnabled(false) , mLock("nsSocketTransportService::mLock") , mInitialized(false) , mShuttingDown(false) , mOffline(false) , mGoingOffline(false) + , mRawThread(nullptr) , mActiveListSize(SOCKET_LIMIT_MIN) , mIdleListSize(SOCKET_LIMIT_MIN) , mActiveCount(0) @@ -133,9 +133,6 @@ nsSocketTransportService::~nsSocketTransportService() { NS_ASSERTION(NS_IsMainThread(), "wrong thread"); NS_ASSERTION(!mInitialized, "not shutdown properly"); - - if (mThreadEvent) - PR_DestroyPollableEvent(mThreadEvent); free(mActiveList); free(mIdleList); @@ -437,7 +434,7 @@ nsSocketTransportService::PollTimeout() } int32_t -nsSocketTransportService::Poll(bool wait, uint32_t *interval, +nsSocketTransportService::Poll(uint32_t *interval, TimeDuration *pollDuration) { PRPollDesc *pollList; @@ -445,11 +442,16 @@ nsSocketTransportService::Poll(bool wait, uint32_t *interval, PRIntervalTime pollTimeout; *pollDuration = 0; + // If there are pending events for this thread then + // DoPollIteration() should service the network without blocking. + bool pendingEvents = false; + mRawThread->HasPendingEvents(&pendingEvents); + if (mPollList[0].fd) { mPollList[0].out_flags = 0; pollList = mPollList; pollCount = mActiveCount + 1; - pollTimeout = PollTimeout(); + pollTimeout = pendingEvents ? PR_INTERVAL_NO_WAIT : PollTimeout(); } else { // no pollable event, so busy wait... @@ -458,12 +460,10 @@ nsSocketTransportService::Poll(bool wait, uint32_t *interval, pollList = &mPollList[1]; else pollList = nullptr; - pollTimeout = PR_MillisecondsToInterval(25); + pollTimeout = + pendingEvents ? PR_INTERVAL_NO_WAIT : PR_MillisecondsToInterval(25); } - if (!wait) - pollTimeout = PR_INTERVAL_NO_WAIT; - PRIntervalTime ts = PR_IntervalNow(); TimeStamp pollStart; @@ -515,19 +515,20 @@ nsSocketTransportService::Init() if (mShuttingDown) return NS_ERROR_UNEXPECTED; - if (!mThreadEvent) { - mThreadEvent = PR_NewPollableEvent(); + if (!mPollableEvent) { + mPollableEvent.reset(new PollableEvent()); // // NOTE: per bug 190000, this failure could be caused by Zone-Alarm // or similar software. // // NOTE: per bug 191739, this failure could also be caused by lack - // of a loopback device on Windows and OS/2 platforms (NSPR creates + // of a loopback device on Windows and OS/2 platforms (it creates // a loopback socket pair on these platforms to implement a pollable // event object). if we can't create a pollable event, then we'll // have to "busy wait" to implement the socket event queue :-( // - if (!mThreadEvent) { + if (!mPollableEvent->Valid()) { + mPollableEvent = nullptr; NS_WARNING("running socket transport thread without a pollable event"); SOCKET_LOG(("running socket transport thread without a pollable event")); } @@ -586,9 +587,9 @@ nsSocketTransportService::Shutdown() // signal the socket thread to shutdown mShuttingDown = true; - if (mThreadEvent) - PR_SetPollableEvent(mThreadEvent); - // else wait for Poll timeout + if (mPollableEvent) { + mPollableEvent->Signal(); + } } // join with thread @@ -639,8 +640,9 @@ nsSocketTransportService::SetOffline(bool offline) else if (mOffline && !offline) { mOffline = false; } - if (mThreadEvent) - PR_SetPollableEvent(mThreadEvent); + if (mPollableEvent) { + mPollableEvent->Signal(); + } return NS_OK; } @@ -763,9 +765,19 @@ nsSocketTransportService::SetAutodialEnabled(bool value) NS_IMETHODIMP nsSocketTransportService::OnDispatchedEvent(nsIThreadInternal *thread) { + if (PR_GetCurrentThread() == gSocketThread) { + // this check is redundant to one done inside ::Signal(), but + // we can do it here and skip obtaining the lock - given that + // this is a relatively common occurance its worth the + // redundant code + SOCKET_LOG(("OnDispatchedEvent Same Thread Skip Signal\n")); + return NS_OK; + } + DebugMutexAutoLock lock(mLock); - if (mThreadEvent) - PR_SetPollableEvent(mThreadEvent); + if (mPollableEvent) { + mPollableEvent->Signal(); + } return NS_OK; } @@ -812,15 +824,15 @@ nsSocketTransportService::Run() gSocketThread = PR_GetCurrentThread(); - // add thread event to poll list (mThreadEvent may be nullptr) - mPollList[0].fd = mThreadEvent; - mPollList[0].in_flags = PR_POLL_READ; + // add thread event to poll list (mPollableEvent may be nullptr) + mPollList[0].fd = mPollableEvent ? mPollableEvent->PollableFD() : nullptr; + mPollList[0].in_flags = PR_POLL_READ | PR_POLL_EXCEPT; mPollList[0].out_flags = 0; - nsIThread *thread = NS_GetCurrentThread(); + mRawThread = NS_GetCurrentThread(); // hook ourselves up to observe event processing for this thread - nsCOMPtr threadInt = do_QueryInterface(thread); + nsCOMPtr threadInt = do_QueryInterface(mRawThread); threadInt->SetObserver(this); // make sure the pseudo random number generator is seeded on this thread @@ -849,7 +861,6 @@ nsSocketTransportService::Run() for (;;) { bool pendingEvents = false; - thread->HasPendingEvents(&pendingEvents); numberOfPendingEvents = 0; numberOfPendingEventsLastCycle = 0; @@ -864,9 +875,7 @@ nsSocketTransportService::Run() pollCycleStart = TimeStamp::NowLoRes(); } - // If there are pending events for this thread then - // DoPollIteration() should service the network without blocking. - DoPollIteration(!pendingEvents, &singlePollDuration); + DoPollIteration(&singlePollDuration); if (mTelemetryEnabledPref && !pollCycleStart.IsNull()) { Telemetry::Accumulate(Telemetry::STS_POLL_BLOCK_TIME, @@ -878,11 +887,7 @@ nsSocketTransportService::Run() pollDuration += singlePollDuration; } - // If nothing was pending before the poll, it might be now - if (!pendingEvents) { - thread->HasPendingEvents(&pendingEvents); - } - + mRawThread->HasPendingEvents(&pendingEvents); if (pendingEvents) { if (!mServingPendingQueue) { nsresult rv = Dispatch(NS_NewRunnableMethod(this, @@ -906,10 +911,10 @@ nsSocketTransportService::Run() } TimeStamp eventQueueStart = TimeStamp::NowLoRes(); do { - NS_ProcessNextEvent(thread); + NS_ProcessNextEvent(mRawThread); numberOfPendingEvents++; pendingEvents = false; - thread->HasPendingEvents(&pendingEvents); + mRawThread->HasPendingEvents(&pendingEvents); } while (pendingEvents && mServingPendingQueue && ((TimeStamp::NowLoRes() - eventQueueStart).ToMilliseconds() < @@ -967,7 +972,7 @@ nsSocketTransportService::Run() // Final pass over the event queue. This makes sure that events posted by // socket detach handlers get processed. - NS_ProcessPendingEvents(thread); + NS_ProcessPendingEvents(mRawThread); gSocketThread = nullptr; @@ -1008,12 +1013,11 @@ nsSocketTransportService::Reset(bool aGuardLocals) } nsresult -nsSocketTransportService::DoPollIteration(bool wait, TimeDuration *pollDuration) +nsSocketTransportService::DoPollIteration(TimeDuration *pollDuration) { - SOCKET_LOG(("STS poll iter [%d]\n", wait)); + SOCKET_LOG(("STS poll iter\n")); int32_t i, count; - // // poll loop // @@ -1068,15 +1072,14 @@ nsSocketTransportService::DoPollIteration(bool wait, TimeDuration *pollDuration) // Measures seconds spent while blocked on PR_Poll uint32_t pollInterval; - int32_t n = 0; #if !defined(MOZILLA_XPCOMRT_API) if (!gIOService->IsNetTearingDown()) { // Let's not do polling during shutdown. - n = Poll(wait, &pollInterval, pollDuration); + n = Poll(&pollInterval, pollDuration); } #else - n = Poll(wait, &pollInterval, pollDuration); + n = Poll(&pollInterval, pollDuration); #endif // defined(MOZILLA_XPCOMRT_API) if (n < 0) { @@ -1132,29 +1135,28 @@ nsSocketTransportService::DoPollIteration(bool wait, TimeDuration *pollDuration) DetachSocket(mActiveList, &mActiveList[i]); } - if (n != 0 && mPollList[0].out_flags == PR_POLL_READ) { - // acknowledge pollable event (wait should not block) - if (PR_WaitForPollableEvent(mThreadEvent) != PR_SUCCESS) { + if (n != 0 && (mPollList[0].out_flags & (PR_POLL_READ | PR_POLL_EXCEPT))) { + DebugMutexAutoLock lock(mLock); + + // acknowledge pollable event (should not block) + if (mPollableEvent && + ((mPollList[0].out_flags & PR_POLL_EXCEPT) || + !mPollableEvent->Clear())) { // On Windows, the TCP loopback connection in the // pollable event may become broken when a laptop // switches between wired and wireless networks or // wakes up from hibernation. We try to create a // new pollable event. If that fails, we fall back // on "busy wait". - { - DebugMutexAutoLock lock(mLock); - PR_DestroyPollableEvent(mThreadEvent); - mThreadEvent = PR_NewPollableEvent(); + NS_WARNING("Trying to repair mPollableEvent"); + mPollableEvent.reset(new PollableEvent()); + if (!mPollableEvent->Valid()) { + mPollableEvent = nullptr; } - if (!mThreadEvent) { - NS_WARNING("running socket transport thread without " - "a pollable event"); - SOCKET_LOG(("running socket transport thread without " - "a pollable event")); - } - mPollList[0].fd = mThreadEvent; - // mPollList[0].in_flags was already set to PR_POLL_READ - // in Run(). + SOCKET_LOG(("running socket transport thread without " + "a pollable event now valid=%d", mPollableEvent->Valid())); + mPollList[0].fd = mPollableEvent ? mPollableEvent->PollableFD() : nullptr; + mPollList[0].in_flags = PR_POLL_READ | PR_POLL_EXCEPT; mPollList[0].out_flags = 0; } } diff --git a/netwerk/base/nsSocketTransportService2.h b/netwerk/base/nsSocketTransportService2.h index 44f514740d50..d1c9ef722824 100644 --- a/netwerk/base/nsSocketTransportService2.h +++ b/netwerk/base/nsSocketTransportService2.h @@ -19,6 +19,8 @@ #include "mozilla/net/DashboardTypes.h" #include "mozilla/Atomics.h" #include "mozilla/TimeStamp.h" +#include "mozilla/UniquePtr.h" +#include "PollableEvent.h" class nsASocketHandler; struct PRPollDesc; @@ -124,14 +126,7 @@ private: //------------------------------------------------------------------------- nsCOMPtr mThread; // protected by mLock - PRFileDesc *mThreadEvent; - // protected by mLock. mThreadEvent may change - // if the old pollable event is broken. only - // the socket thread may change mThreadEvent; - // it needs to lock mLock only when it changes - // mThreadEvent. other threads don't change - // mThreadEvent; they need to lock mLock - // whenever they access mThreadEvent. + mozilla::UniquePtr mPollableEvent; bool mAutodialEnabled; // pref to control autodial code @@ -173,6 +168,7 @@ private: SocketContext *mActiveList; /* mListSize entries */ SocketContext *mIdleList; /* mListSize entries */ + nsIThread *mRawThread; uint32_t mActiveListSize; uint32_t mIdleListSize; @@ -197,18 +193,16 @@ private: //------------------------------------------------------------------------- // poll list (socket thread only) // - // first element of the poll list is mThreadEvent (or null if the pollable + // first element of the poll list is mPollableEvent (or null if the pollable // event cannot be created). //------------------------------------------------------------------------- PRPollDesc *mPollList; /* mListSize + 1 entries */ PRIntervalTime PollTimeout(); // computes ideal poll timeout - nsresult DoPollIteration(bool wait, - mozilla::TimeDuration *pollDuration); + nsresult DoPollIteration(mozilla::TimeDuration *pollDuration); // perfoms a single poll iteration - int32_t Poll(bool wait, - uint32_t *interval, + int32_t Poll(uint32_t *interval, mozilla::TimeDuration *pollDuration); // calls PR_Poll. the out param // interval indicates the poll diff --git a/netwerk/cache2/CacheIndex.cpp b/netwerk/cache2/CacheIndex.cpp index 64e38c1d3205..3c46edd240ba 100644 --- a/netwerk/cache2/CacheIndex.cpp +++ b/netwerk/cache2/CacheIndex.cpp @@ -347,13 +347,15 @@ CacheIndex::PreShutdown() nsCOMPtr event; event = NS_NewRunnableMethod(index, &CacheIndex::PreShutdownInternal); - nsCOMPtr ioTarget = CacheFileIOManager::IOTarget(); - MOZ_ASSERT(ioTarget); + RefPtr ioThread = CacheFileIOManager::IOThread(); + MOZ_ASSERT(ioThread); - // PreShutdownInternal() will be executed before any queued event on INDEX - // level. That's OK since we don't want to wait for any operation in progess. - // We need to interrupt it and save journal as quickly as possible. - rv = ioTarget->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL); + // Executing PreShutdownInternal() on WRITE level ensures that read/write + // events holding pointer to mRWBuf will be executed before we release the + // buffer by calling FinishRead()/FinishWrite() in PreShutdownInternal(), but + // it will be executed before any queued event on INDEX level. That's OK since + // we don't want to wait until updating of the index finishes. + rv = ioThread->Dispatch(event, CacheIOThread::WRITE); if (NS_FAILED(rv)) { NS_WARNING("CacheIndex::PreShutdown() - Can't dispatch event"); LOG(("CacheIndex::PreShutdown() - Can't dispatch event" )); diff --git a/netwerk/cache2/CacheObserver.cpp b/netwerk/cache2/CacheObserver.cpp index 282ae13f0e98..2b772bb3546b 100644 --- a/netwerk/cache2/CacheObserver.cpp +++ b/netwerk/cache2/CacheObserver.cpp @@ -503,18 +503,13 @@ CacheObserver::Observe(nsISupports* aSubject, return NS_OK; } - if (!strcmp(aTopic, "profile-before-change")) { + if (!strcmp(aTopic, "profile-change-net-teardown") || + !strcmp(aTopic, "profile-before-change") || + !strcmp(aTopic, "xpcom-shutdown")) { RefPtr service = CacheStorageService::Self(); - if (service) - service->Shutdown(); - - return NS_OK; - } - - if (!strcmp(aTopic, "xpcom-shutdown")) { - RefPtr service = CacheStorageService::Self(); - if (service) + if (service) { service->Shutdown(); + } CacheFileIOManager::Shutdown(); return NS_OK; @@ -522,8 +517,9 @@ CacheObserver::Observe(nsISupports* aSubject, if (!strcmp(aTopic, "last-pb-context-exited")) { RefPtr service = CacheStorageService::Self(); - if (service) + if (service) { service->DropPrivateBrowsingEntries(); + } return NS_OK; } diff --git a/netwerk/cache2/CacheStorageService.cpp b/netwerk/cache2/CacheStorageService.cpp index a3dd75d2e3da..22cce5cff8e7 100644 --- a/netwerk/cache2/CacheStorageService.cpp +++ b/netwerk/cache2/CacheStorageService.cpp @@ -1239,6 +1239,16 @@ CacheStorageService::PurgeOverMemoryLimit() LOG(("CacheStorageService::PurgeOverMemoryLimit")); + static TimeDuration const kFourSeconds = TimeDuration::FromSeconds(4); + TimeStamp now = TimeStamp::NowLoRes(); + + if (!mLastPurgeTime.IsNull() && now - mLastPurgeTime < kFourSeconds) { + LOG((" bypassed, too soon")); + return; + } + + mLastPurgeTime = now; + Pool(true).PurgeOverMemoryLimit(); Pool(false).PurgeOverMemoryLimit(); } diff --git a/netwerk/cache2/CacheStorageService.h b/netwerk/cache2/CacheStorageService.h index d8bbdd3c84e1..7da8297067e9 100644 --- a/netwerk/cache2/CacheStorageService.h +++ b/netwerk/cache2/CacheStorageService.h @@ -312,7 +312,7 @@ private: nsTArray > mFrecencyArray; nsTArray > mExpirationArray; - mozilla::Atomic mMemorySize; + Atomic mMemorySize; bool OnMemoryConsumptionChange(uint32_t aSavedMemorySize, uint32_t aCurrentMemoryConsumption); @@ -331,6 +331,7 @@ private: MemoryPool mDiskPool; MemoryPool mMemoryPool; + TimeStamp mLastPurgeTime; MemoryPool& Pool(bool aUsingDisk) { return aUsingDisk ? mDiskPool : mMemoryPool; diff --git a/netwerk/dns/ChildDNSService.cpp b/netwerk/dns/ChildDNSService.cpp index d202c68fceb6..a7b49679e3ea 100644 --- a/netwerk/dns/ChildDNSService.cpp +++ b/netwerk/dns/ChildDNSService.cpp @@ -4,11 +4,13 @@ #include "mozilla/net/ChildDNSService.h" #include "nsIDNSListener.h" +#include "nsIIOService.h" #include "nsIThread.h" #include "nsThreadUtils.h" #include "nsIXPConnect.h" #include "nsIPrefService.h" #include "nsIProtocolProxyService.h" +#include "nsNetCID.h" #include "mozilla/net/NeckoChild.h" #include "mozilla/net/DNSListenerProxy.h" #include "nsServiceManagerUtils.h" @@ -42,7 +44,6 @@ NS_IMPL_ISUPPORTS(ChildDNSService, ChildDNSService::ChildDNSService() : mFirstTime(true) - , mOffline(false) , mDisablePrefetch(false) , mPendingRequestsLock("DNSPendingRequestsLock") { @@ -103,7 +104,7 @@ ChildDNSService::AsyncResolveExtended(const nsACString &hostname, // Support apps being 'offline' even if parent is not: avoids DNS traffic by // apps that have been told they are offline. - if (mOffline) { + if (GetOffline()) { flags |= RESOLVE_OFFLINE; } @@ -298,18 +299,15 @@ ChildDNSService::SetPrefetchEnabled(bool inVal) return NS_OK; } -NS_IMETHODIMP -ChildDNSService::GetOffline(bool* aResult) +bool +ChildDNSService::GetOffline() const { - *aResult = mOffline; - return NS_OK; -} - -NS_IMETHODIMP -ChildDNSService::SetOffline(bool value) -{ - mOffline = value; - return NS_OK; + bool offline = false; + nsCOMPtr io = do_GetService(NS_IOSERVICE_CONTRACTID); + if (io) { + io->GetOffline(&offline); + } + return offline; } //----------------------------------------------------------------------------- diff --git a/netwerk/dns/ChildDNSService.h b/netwerk/dns/ChildDNSService.h index b2c3a1dbcc1e..1662960bbec0 100644 --- a/netwerk/dns/ChildDNSService.h +++ b/netwerk/dns/ChildDNSService.h @@ -35,6 +35,8 @@ public: static ChildDNSService* GetSingleton(); void NotifyRequestDone(DNSRequestChild *aDnsRequest); + + bool GetOffline() const; private: virtual ~ChildDNSService(); @@ -45,7 +47,6 @@ private: nsACString &aHashKey); bool mFirstTime; - bool mOffline; bool mDisablePrefetch; // We need to remember pending dns requests to be able to cancel them. diff --git a/netwerk/dns/nsDNSService2.cpp b/netwerk/dns/nsDNSService2.cpp index 172405da6985..6659c03b22be 100644 --- a/netwerk/dns/nsDNSService2.cpp +++ b/netwerk/dns/nsDNSService2.cpp @@ -483,7 +483,6 @@ nsDNSService::nsDNSService() , mDisableIPv6(false) , mDisablePrefetch(false) , mFirstTime(true) - , mOffline(false) , mNotifyResolution(false) , mOfflineLocalhost(false) { @@ -677,18 +676,15 @@ nsDNSService::Shutdown() return NS_OK; } -NS_IMETHODIMP -nsDNSService::GetOffline(bool *offline) +bool +nsDNSService::GetOffline() const { - *offline = mOffline; - return NS_OK; -} - -NS_IMETHODIMP -nsDNSService::SetOffline(bool offline) -{ - mOffline = offline; - return NS_OK; + bool offline = false; + nsCOMPtr io = do_GetService(NS_IOSERVICE_CONTRACTID); + if (io) { + io->GetOffline(&offline); + } + return offline; } NS_IMETHODIMP @@ -784,7 +780,7 @@ nsDNSService::AsyncResolveExtended(const nsACString &aHostname, return rv; } - if (mOffline && + if (GetOffline() && (!mOfflineLocalhost || !hostname.LowerCaseEqualsASCII("localhost"))) { flags |= RESOLVE_OFFLINE; } @@ -899,7 +895,7 @@ nsDNSService::Resolve(const nsACString &aHostname, return rv; } - if (mOffline && + if (GetOffline() && (!mOfflineLocalhost || !hostname.LowerCaseEqualsASCII("localhost"))) { flags |= RESOLVE_OFFLINE; } diff --git a/netwerk/dns/nsDNSService2.h b/netwerk/dns/nsDNSService2.h index a33e2dd9b48a..79454b901b3f 100644 --- a/netwerk/dns/nsDNSService2.h +++ b/netwerk/dns/nsDNSService2.h @@ -36,6 +36,8 @@ public: size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; + bool GetOffline() const; + private: ~nsDNSService(); @@ -62,7 +64,6 @@ private: bool mDisablePrefetch; bool mBlockDotOnion; bool mFirstTime; - bool mOffline; bool mNotifyResolution; bool mOfflineLocalhost; nsTHashtable mLocalDomains; diff --git a/netwerk/dns/nsPIDNSService.idl b/netwerk/dns/nsPIDNSService.idl index d89f1bdfb841..9bed0555c5ef 100644 --- a/netwerk/dns/nsPIDNSService.idl +++ b/netwerk/dns/nsPIDNSService.idl @@ -10,7 +10,7 @@ * This is a private interface used by the internals of the networking library. * It will never be frozen. Do not use it in external code. */ -[scriptable, uuid(6b16fb1f-5709-4c94-a89f-a22be873c54d)] +[scriptable, uuid(24e598fd-7b1a-436c-9154-14d8b38df8a5)] interface nsPIDNSService : nsIDNSService { /** @@ -31,9 +31,4 @@ interface nsPIDNSService : nsIDNSService * Whether or not DNS prefetching (aka RESOLVE_SPECULATE) is enabled */ attribute boolean prefetchEnabled; - - /** - * @return whether the DNS service is offline. - */ - attribute boolean offline; }; diff --git a/netwerk/protocol/http/ASpdySession.h b/netwerk/protocol/http/ASpdySession.h index b8d9899a6eb8..ec5d2c885d16 100644 --- a/netwerk/protocol/http/ASpdySession.h +++ b/netwerk/protocol/http/ASpdySession.h @@ -68,7 +68,7 @@ public: // this could go either way, but because there are network instances of // it being a hard error we should consider it hard. - if (code == NS_ERROR_FAILURE) { + if (code == NS_ERROR_FAILURE || code == NS_ERROR_OUT_OF_MEMORY) { return false; } diff --git a/netwerk/protocol/http/Http2Stream.cpp b/netwerk/protocol/http/Http2Stream.cpp index 40df0f262e41..73d41a1550b8 100644 --- a/netwerk/protocol/http/Http2Stream.cpp +++ b/netwerk/protocol/http/Http2Stream.cpp @@ -235,28 +235,12 @@ Http2Stream::ReadSegments(nsAHttpSegmentReader *reader, return rv; } -static bool -IsDataAvailable(nsIInputStream *stream) -{ - if (!stream) { - return false; - } - uint64_t avail; - if (NS_FAILED(stream->Available(&avail))) { - return false; - } - return (avail > 0); -} - uint64_t Http2Stream::LocalUnAcked() { // reduce unacked by the amount of undelivered data // to help assert flow control - uint64_t undelivered = 0; - if (mInputBufferIn) { - mInputBufferIn->Available(&undelivered); - } + uint64_t undelivered = mSimpleBuffer.Available(); if (undelivered > mLocalUnacked) { return 0; @@ -267,25 +251,20 @@ Http2Stream::LocalUnAcked() nsresult Http2Stream::BufferInput(uint32_t count, uint32_t *countWritten) { - static const uint32_t segmentSize = 32768; - char buf[segmentSize]; - - count = std::min(segmentSize, count); - if (!mInputBufferOut) { - NS_NewPipe(getter_AddRefs(mInputBufferIn), getter_AddRefs(mInputBufferOut), - segmentSize, UINT32_MAX); - if (!mInputBufferOut) { - return NS_ERROR_OUT_OF_MEMORY; - } + char buf[SimpleBufferPage::kSimpleBufferPageSize]; + if (SimpleBufferPage::kSimpleBufferPageSize < count) { + count = SimpleBufferPage::kSimpleBufferPageSize; } + mBypassInputBuffer = 1; nsresult rv = mSegmentWriter->OnWriteSegment(buf, count, countWritten); mBypassInputBuffer = 0; + if (NS_SUCCEEDED(rv)) { - uint32_t buffered; - rv = mInputBufferOut->Write(buf, *countWritten, &buffered); - if (NS_SUCCEEDED(rv) && (buffered != *countWritten)) { - rv = NS_ERROR_OUT_OF_MEMORY; + rv = mSimpleBuffer.Write(buf, *countWritten); + if (NS_FAILED(rv)) { + MOZ_ASSERT(rv == NS_ERROR_OUT_OF_MEMORY); + return NS_ERROR_OUT_OF_MEMORY; } } return rv; @@ -295,7 +274,7 @@ bool Http2Stream::DeferCleanup(nsresult status) { // do not cleanup a stream that has data buffered for the transaction - return (NS_SUCCEEDED(status) && IsDataAvailable(mInputBufferIn)); + return (NS_SUCCEEDED(status) && mSimpleBuffer.Available()); } // WriteSegments() is used to read data off the socket. Generally this is @@ -1432,16 +1411,12 @@ Http2Stream::OnWriteSegment(char *buf, // so that other streams can proceed when the gecko caller is not processing // data events fast enough and flow control hasn't caught up yet. This // gets the stored data out of that pipe - if (!mBypassInputBuffer && IsDataAvailable(mInputBufferIn)) { - nsresult rv = mInputBufferIn->Read(buf, count, countWritten); + if (!mBypassInputBuffer && mSimpleBuffer.Available()) { + *countWritten = mSimpleBuffer.Read(buf, count); + MOZ_ASSERT(*countWritten); LOG3(("Http2Stream::OnWriteSegment read from flow control buffer %p %x %d\n", this, mStreamID, *countWritten)); - if (!IsDataAvailable(mInputBufferIn)) { - // drop the pipe if we don't need it anymore - mInputBufferIn = nullptr; - mInputBufferOut = nullptr; - } - return rv; + return NS_OK; } // read from the network diff --git a/netwerk/protocol/http/Http2Stream.h b/netwerk/protocol/http/Http2Stream.h index ca542672bb84..5cb1d15ad7c3 100644 --- a/netwerk/protocol/http/Http2Stream.h +++ b/netwerk/protocol/http/Http2Stream.h @@ -13,6 +13,7 @@ #include "mozilla/UniquePtr.h" #include "nsAHttpTransaction.h" #include "nsISupportsPriority.h" +#include "SimpleBuffer.h" class nsStandardURL; class nsIInputStream; @@ -325,10 +326,9 @@ private: // For Http2Push Http2PushedStream *mPushSource; - // A pipe used to store stream data when the transaction cannot keep up + // Used to store stream data when the transaction channel cannot keep up // and flow control has not yet kicked in. - nsCOMPtr mInputBufferIn; - nsCOMPtr mInputBufferOut; + SimpleBuffer mSimpleBuffer; /// connect tunnels public: diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index a638b4809fcb..5c3a5f3df578 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -2076,7 +2076,8 @@ nsHttpChannel::OpenRedirectChannel(nsresult rv) { AutoRedirectVetoNotifier notifier(this); - // Make sure to do this _after_ calling OnChannelRedirect + // Make sure to do this after we received redirect veto answer, + // i.e. after all sinks had been notified mRedirectChannel->SetOriginalURI(mOriginalURI); // And now, notify observers the deprecated way @@ -2156,7 +2157,8 @@ nsHttpChannel::ContinueDoReplaceWithProxy(nsresult rv) NS_PRECONDITION(mRedirectChannel, "No redirect channel?"); - // Make sure to do this _after_ calling OnChannelRedirect + // Make sure to do this after we received redirect veto answer, + // i.e. after all sinks had been notified mRedirectChannel->SetOriginalURI(mOriginalURI); // open new channel @@ -2823,7 +2825,8 @@ nsHttpChannel::ContinueProcessFallback(nsresult rv) NS_PRECONDITION(mRedirectChannel, "No redirect channel?"); - // Make sure to do this _after_ calling OnChannelRedirect + // Make sure to do this after we received redirect veto answer, + // i.e. after all sinks had been notified mRedirectChannel->SetOriginalURI(mOriginalURI); if (mLoadInfo && mLoadInfo->GetEnforceSecurity()) { @@ -4765,7 +4768,8 @@ nsHttpChannel::ContinueProcessRedirection(nsresult rv) NS_PRECONDITION(mRedirectChannel, "No redirect channel?"); - // Make sure to do this _after_ calling OnChannelRedirect + // Make sure to do this after we received redirect veto answer, + // i.e. after all sinks had been notified mRedirectChannel->SetOriginalURI(mOriginalURI); // And now, the deprecated way diff --git a/netwerk/sctp/datachannel/DataChannel.cpp b/netwerk/sctp/datachannel/DataChannel.cpp index 5385c9e83219..48d1fc4db1a6 100644 --- a/netwerk/sctp/datachannel/DataChannel.cpp +++ b/netwerk/sctp/datachannel/DataChannel.cpp @@ -1778,7 +1778,7 @@ DataChannelConnection::HandleStreamResetEvent(const struct sctp_stream_reset_eve LOG(("Disconnected DataChannel %p from connection %p", (void *) channel.get(), (void *) channel->mConnection.get())); - channel->Destroy(); + channel->DestroyLocked(); // At this point when we leave here, the object is a zombie held alive only by the DOM object } else { LOG(("Can't find incoming channel %d",i)); @@ -2502,7 +2502,7 @@ DataChannelConnection::CloseInt(DataChannel *aChannel) aChannel->mState = CLOSING; if (mState == CLOSED) { // we're not going to hang around waiting - channel->Destroy(); + channel->DestroyLocked(); } // At this point when we leave here, the object is a zombie held alive only by the DOM object } @@ -2556,13 +2556,15 @@ void DataChannel::Close() { ENSURE_DATACONNECTION; + RefPtr connection(mConnection); mConnection->Close(this); } // Used when disconnecting from the DataChannelConnection void -DataChannel::Destroy() +DataChannel::DestroyLocked() { + mConnection->mLock.AssertCurrentThreadOwns(); ENSURE_DATACONNECTION; LOG(("Destroying Data channel %u", mStream)); diff --git a/netwerk/sctp/datachannel/DataChannel.h b/netwerk/sctp/datachannel/DataChannel.h index 2ccdc48a835d..6386dbb498df 100644 --- a/netwerk/sctp/datachannel/DataChannel.h +++ b/netwerk/sctp/datachannel/DataChannel.h @@ -337,10 +337,11 @@ private: ~DataChannel(); public: - void Destroy(); // when we disconnect from the connection after stream RESET - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DataChannel) + // when we disconnect from the connection after stream RESET + void DestroyLocked(); + // Close this DataChannel. Can be called multiple times. MUST be called // before destroying the DataChannel (state must be CLOSED or CLOSING). void Close(); diff --git a/netwerk/standalone/moz.build b/netwerk/standalone/moz.build index 60a16aa26783..1fd8b8992be2 100644 --- a/netwerk/standalone/moz.build +++ b/netwerk/standalone/moz.build @@ -12,6 +12,7 @@ src_list = [ ] netwerk_base_src = [ + 'PollableEvent.cpp', 'nsDNSPrefetch.cpp', 'nsNetAddr.cpp', 'nsSocketTransportService2.cpp', diff --git a/python/mozbuild/mozbuild/frontend/sandbox.py b/python/mozbuild/mozbuild/frontend/sandbox.py index 0ae8e30daefb..9f2666f8c51b 100644 --- a/python/mozbuild/mozbuild/frontend/sandbox.py +++ b/python/mozbuild/mozbuild/frontend/sandbox.py @@ -286,6 +286,10 @@ class Sandbox(dict): if key in self._context and self._context[key] is not value: raise KeyError('global_ns', 'reassign', key) + if (key not in self._context and isinstance(value, (list, dict)) + and not value): + raise KeyError('Variable %s assigned an empty value.' % key) + self._context[key] = value else: dict.__setitem__(self, key, value) diff --git a/python/mozbuild/mozbuild/test/frontend/data/reader-error-empty-list/moz.build b/python/mozbuild/mozbuild/test/frontend/data/reader-error-empty-list/moz.build new file mode 100644 index 000000000000..fc4ce0217978 --- /dev/null +++ b/python/mozbuild/mozbuild/test/frontend/data/reader-error-empty-list/moz.build @@ -0,0 +1,5 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# Any copyright is dedicated to the Public Domain. +# http://creativecommons.org/publicdomain/zero/1.0/ + +DIRS = [] diff --git a/python/mozbuild/mozbuild/test/frontend/test_reader.py b/python/mozbuild/mozbuild/test/frontend/test_reader.py index 730588b71823..d50a0658354a 100644 --- a/python/mozbuild/mozbuild/test/frontend/test_reader.py +++ b/python/mozbuild/mozbuild/test/frontend/test_reader.py @@ -11,8 +11,10 @@ import unittest from mozunit import main from mozbuild.frontend.context import BugzillaComponent -from mozbuild.frontend.reader import BuildReaderError -from mozbuild.frontend.reader import BuildReader +from mozbuild.frontend.reader import ( + BuildReaderError, + BuildReader, +) from mozbuild.test.common import MockConfig @@ -246,6 +248,15 @@ class TestBuildReader(unittest.TestCase): contexts = list(reader.read_topsrcdir()) + def test_error_empty_list(self): + reader = self.reader('reader-error-empty-list') + + with self.assertRaises(BuildReaderError) as bre: + list(reader.read_topsrcdir()) + + e = bre.exception + self.assertIn('Variable DIRS assigned an empty value.', str(e)) + def test_inheriting_variables(self): reader = self.reader('inheriting-variables') diff --git a/testing/mochitest/runtests.py b/testing/mochitest/runtests.py index ef30a99accb4..c6889db88c07 100644 --- a/testing/mochitest/runtests.py +++ b/testing/mochitest/runtests.py @@ -31,6 +31,7 @@ import tempfile import time import traceback import urllib2 +import uuid import zipfile import bisection @@ -1210,8 +1211,6 @@ toolbar#nav-bar { self.nsprLogs = NSPR_LOG_MODULES and "MOZ_UPLOAD_DIR" in os.environ if self.nsprLogs: browserEnv["NSPR_LOG_MODULES"] = NSPR_LOG_MODULES - - browserEnv["NSPR_LOG_FILE"] = "%s/nspr.log" % tempfile.gettempdir() browserEnv["GECKO_SEPARATE_NSPR_LOGS"] = "1" if debugger and not options.slowscript: @@ -2288,6 +2287,9 @@ class MochitestDesktop(MochitestBase): if self.browserEnv is None: return 1 + if self.nsprLogs: + self.browserEnv["NSPR_LOG_FILE"] = "{}/nspr-pid=%PID-uid={}.log".format(self.browserEnv["MOZ_UPLOAD_DIR"], str(uuid.uuid4())) + try: self.startServers(options, debuggerInfo) @@ -2400,14 +2402,6 @@ class MochitestDesktop(MochitestBase): options.symbolsPath), ) - if self.nsprLogs: - with zipfile.ZipFile("%s/nsprlog.zip" % self.browserEnv["MOZ_UPLOAD_DIR"], "w", zipfile.ZIP_DEFLATED) as logzip: - for logfile in glob.glob( - "%s/nspr*.log*" % - tempfile.gettempdir()): - logzip.write(logfile) - os.remove(logfile) - self.log.info("runtests.py | Running tests: end.") if self.manifest is not None: @@ -2654,6 +2648,14 @@ def run_test_harness(options): result = runner.runTests(options) + if runner.nsprLogs: + with zipfile.ZipFile("{}/nsprlogs.zip".format(runner.browserEnv["MOZ_UPLOAD_DIR"]), + "w", zipfile.ZIP_DEFLATED) as logzip: + for logfile in glob.glob("{}/nspr*.log*".format(runner.browserEnv["MOZ_UPLOAD_DIR"])): + logzip.write(logfile) + os.remove(logfile) + logzip.close() + # don't dump failures if running from automation as treeherder already displays them if build_obj: if runner.message_logger.errors: diff --git a/testing/mochitest/tests/Harness_sanity/test_createFiles.html b/testing/mochitest/tests/Harness_sanity/test_createFiles.html index f3a7a53175ef..502592acc9e0 100644 --- a/testing/mochitest/tests/Harness_sanity/test_createFiles.html +++ b/testing/mochitest/tests/Harness_sanity/test_createFiles.html @@ -11,14 +11,16 @@ + + + +
+ + + + + \ No newline at end of file diff --git a/testing/web-platform/tests/web-animations/keyframe-effect/constructor.html b/testing/web-platform/tests/web-animations/keyframe-effect/constructor.html index 184da113e463..832b2471eedb 100644 --- a/testing/web-platform/tests/web-animations/keyframe-effect/constructor.html +++ b/testing/web-platform/tests/web-animations/keyframe-effect/constructor.html @@ -474,12 +474,8 @@ test(function(t) { var gKeyframeEffectOptionTests = [ { desc: "an empty KeyframeEffectOptions object", - input: {}, - expected: { delay: 0, - fill: "auto", - iterations: 1, - duration: "auto", - direction: "normal" } }, + input: { }, + expected: { } }, { desc: "a normal KeyframeEffectOptions object", input: { delay: 1000, fill: "auto", @@ -493,123 +489,55 @@ var gKeyframeEffectOptionTests = [ direction: "alternate" } }, { desc: "a double value", input: 3000, - expected: { delay: 0, - fill: "auto", - iterations: 1, - duration: 3000, - direction: "normal" } }, + expected: { duration: 3000 } }, { desc: "+Infinity", input: Infinity, - expected: { delay: 0, - fill: "auto", - iterations: 1, - duration: Infinity, - direction: "normal" } }, + expected: { duration: Infinity } }, { desc: "-Infinity", input: -Infinity, - expected: { delay: 0, - fill: "auto", - iterations: 1, - duration: -Infinity, - direction: "normal" } }, + expected: { duration: -Infinity } }, { desc: "NaN", input: NaN, - expected: { delay: 0, - fill: "auto", - iterations: 1, - duration: NaN, - direction: "normal" } }, + expected: { duration: NaN } }, { desc: "a negative value", input: -1, - expected: { delay: 0, - fill: "auto", - iterations: 1, - duration: -1, - direction: "normal" } }, + expected: { duration: -1 } }, { desc: "an Infinity duration", input: { duration: Infinity }, - expected: { delay: 0, - fill: "auto", - iterations: 1, - duration: Infinity, - direction: "normal" } }, + expected: { duration: Infinity } }, { desc: "a negative Infinity duration", input: { duration: -Infinity }, - expected: { delay: 0, - fill: "auto", - iterations: 1, - duration: -Infinity, - direction: "normal" } }, + expected: { duration: -Infinity } }, { desc: "a NaN duration", input: { duration: NaN }, - expected: { delay: 0, - fill: "auto", - iterations: 1, - duration: NaN, - direction: "normal" } }, + expected: { duration: NaN } }, { desc: "a negative duration", input: { duration: -1 }, - expected: { delay: 0, - fill: "auto", - iterations: 1, - duration: -1, - direction: "normal" } }, + expected: { duration: -1 } }, { desc: "a string duration", input: { duration: "merrychristmas" }, - expected: { delay: 0, - fill: "auto", - iterations: 1, - duration: "merrychristmas", - direction: "normal" } }, + expected: { duration: "merrychristmas" } }, { desc: "an auto duration", input: { duration: "auto" }, - expected: { delay: 0, - fill: "auto", - iterations: 1, - duration: "auto", - direction: "normal" } }, + expected: { duration: "auto" } }, { desc: "an Infinity iterations", input: { iterations: Infinity }, - expected: { delay: 0, - fill: "auto", - iterations: Infinity, - duration: "auto", - direction: "normal" } }, + expected: { iterations: Infinity } }, { desc: "a negative Infinity iterations", input: { iterations: -Infinity }, - expected: { delay: 0, - fill: "auto", - iterations: -Infinity, - duration: "auto", - direction: "normal" } }, + expected: { iterations: -Infinity } }, { desc: "a NaN iterations", input: { iterations: NaN }, - expected: { delay: 0, - fill: "auto", - iterations: NaN, - duration: "auto", - direction: "normal" } }, + expected: { iterations: NaN } }, { desc: "a negative iterations", input: { iterations: -1 }, - expected: { delay: 0, - fill: "auto", - iterations: -1, - duration: "auto", - direction: "normal" } }, + expected: { iterations: -1 } }, { desc: "an auto fill", input: { fill: "auto" }, - expected: { delay: 0, - fill: "auto", - iterations: 1, - duration: "auto", - direction: "normal" } }, + expected: { fill: "auto" } }, { desc: "a forwards fill", input: { fill: "forwards" }, - expected: { delay: 0, - fill: "forwards", - iterations: 1, - duration: "auto", - direction: "normal" } } + expected: { fill: "forwards" } } ]; gKeyframeEffectOptionTests.forEach(function(stest) { @@ -618,14 +546,24 @@ gKeyframeEffectOptionTests.forEach(function(stest) { {left: ["10px", "20px"]}, stest.input); + // Helper function to provide default expected values when the test does + // not supply them. + var expected = function(field, defaultValue) { + return field in stest.expected ? stest.expected[field] : defaultValue; + }; + var timing = effect.timing; - assert_equals(timing.delay, stest.expected.delay, "timing delay"); - assert_equals(timing.fill, stest.expected.fill, "timing fill"); - assert_equals(timing.iterations, stest.expected.iterations, + assert_equals(timing.delay, expected("delay", 0), + "timing delay"); + assert_equals(timing.fill, expected("fill", "auto"), + "timing fill"); + assert_equals(timing.iterations, expected("iterations", 1), "timing iterations"); - assert_equals(timing.duration, stest.expected.duration, "timing duration"); - assert_equals(timing.direction, stest.expected.direction, + assert_equals(timing.duration, expected("duration", "auto"), + "timing duration"); + assert_equals(timing.direction, expected("direction", "normal"), "timing direction"); + }, "a KeyframeEffectReadOnly constructed by " + stest.desc); }); diff --git a/testing/web-platform/tests/web-animations/keyframe-effect/getComputedTiming.html b/testing/web-platform/tests/web-animations/keyframe-effect/getComputedTiming.html index 1b0f276740b7..7412824e7eee 100644 --- a/testing/web-platform/tests/web-animations/keyframe-effect/getComputedTiming.html +++ b/testing/web-platform/tests/web-animations/keyframe-effect/getComputedTiming.html @@ -30,12 +30,8 @@ test(function(t) { var gGetComputedTimingTests = [ { desc: "an empty KeyframeEffectOptions object", - input: {}, - expected: { delay: 0, - fill: "none", - iterations: 1, - duration: 0, - direction: "normal" } }, + input: { }, + expected: { } }, { desc: "a normal KeyframeEffectOptions object", input: { delay: 1000, fill: "auto", @@ -47,13 +43,9 @@ var gGetComputedTimingTests = [ iterations: 5.5, duration: 0, direction: "alternate" } }, - { desc: " a double value", + { desc: "a double value", input: 3000, - timing: { delay: 0, - fill: "auto", - iterations: 1, - duration: 3000, - direction: "normal" }, + timing: { duration: 3000 }, expected: { delay: 0, fill: "none", iterations: 1, @@ -61,116 +53,52 @@ var gGetComputedTimingTests = [ direction: "normal" } }, { desc: "+Infinity", input: Infinity, - expected: { delay: 0, - fill: "none", - iterations: 1, - duration: Infinity, - direction: "normal" } }, + expected: { duration: Infinity } }, { desc: "-Infinity", input: -Infinity, - expected: { delay: 0, - fill: "none", - iterations: 1, - duration: 0, - direction: "normal" } }, + expected: { duration: 0 } }, { desc: "NaN", input: NaN, - expected: { delay: 0, - fill: "none", - iterations: 1, - duration: 0, - direction: "normal" } }, + expected: { duration: 0 } }, { desc: "a negative value", input: -1, - expected: { delay: 0, - fill: "none", - iterations: 1, - duration: 0, - direction: "normal" } }, + expected: { duration: 0 } }, { desc: "an Infinity duration", input: { duration: Infinity }, - expected: { delay: 0, - fill: "none", - iterations: 1, - duration: Infinity, - direction: "normal" } }, + expected: { duration: Infinity } }, { desc: "a negative Infinity duration", input: { duration: -Infinity }, - expected: { delay: 0, - fill: "none", - iterations: 1, - duration: 0, - direction: "normal" } }, + expected: { duration: 0 } }, { desc: "a NaN duration", input: { duration: NaN }, - expected: { delay: 0, - fill: "none", - iterations: 1, - duration: 0, - direction: "normal" } }, + expected: { duration: 0 } }, { desc: "a negative duration", input: { duration: -1}, - expected: { delay: 0, - fill: "none", - iterations: 1, - duration: 0, - direction: "normal" } }, + expected: { duration: 0 } }, { desc: "a string duration", input: { duration: "merrychristmas"}, - expected: { delay: 0, - fill: "none", - iterations: 1, - duration: 0, - direction: "normal" } }, + expected: { duration: 0 } }, { desc: "an auto duration", input: { duration: "auto" }, - expected: { delay: 0, - fill: "none", - iterations: 1, - duration: 0, - direction: "normal" } }, + expected: { duration: 0 } }, { desc: "an Infinity iterations", input: { iterations: Infinity }, - expected: { delay: 0, - fill: "none", - iterations: Infinity, - duration: 0, - direction: "normal" } }, + expected: { iterations: Infinity } }, { desc: "a negative Infinity iterations", input: { iterations: -Infinity}, - expected: { delay: 0, - fill: "none", - iterations: 1, - duration: 0, - direction: "normal" } }, + expected: { iterations: 1 } }, { desc: "a NaN iterations", input: { iterations: NaN }, - expected: { delay: 0, - fill: "none", - iterations: 1, - duration: 0, - direction: "normal" } }, + expected: { iterations: 1 } }, { desc: "a negative iterations", input: { iterations: -1 }, - expected: { delay: 0, - fill: "none", - iterations: 1, - duration: 0, - direction: "normal" } }, + expected: { iterations: 1 } }, { desc: "an auto fill", input: { fill: "auto" }, - expected: { delay: 0, - fill: "none", - iterations: 1, - duration: 0, - direction: "normal" } }, + expected: { fill: "none" } }, { desc: "a forwards fill", input: { fill: "forwards" }, - expected: { delay: 0, - fill: "forwards", - iterations: 1, - duration: 0, - direction: "normal" } } + expected: { fill: "forwards" } } ]; gGetComputedTimingTests.forEach(function(stest) { @@ -179,17 +107,149 @@ gGetComputedTimingTests.forEach(function(stest) { { left: ["10px", "20px"] }, stest.input); + // Helper function to provide default expected values when the test does + // not supply them. + var expected = function(field, defaultValue) { + return field in stest.expected ? stest.expected[field] : defaultValue; + }; + var ct = effect.getComputedTiming(); - assert_equals(ct.delay, stest.expected.delay, "computed delay"); - assert_equals(ct.fill, stest.expected.fill, "computed fill"); - assert_equals(ct.iterations, stest.expected.iterations, + assert_equals(ct.delay, expected("delay", 0), + "computed delay"); + assert_equals(ct.fill, expected("fill", "none"), + "computed fill"); + assert_equals(ct.iterations, expected("iterations", 1), "computed iterations"); - assert_equals(ct.duration, stest.expected.duration, "computed duration"); - assert_equals(ct.direction, stest.expected.direction, "computed direction"); + assert_equals(ct.duration, expected("duration", 0), + "computed duration"); + assert_equals(ct.direction, expected("direction", "normal"), + "computed direction"); + }, "values of getComputedTiming() when a KeyframeEffectReadOnly is " + "constructed by " + stest.desc); }); +var gActiveDurationTests = [ + { desc: "an empty KeyframeEffectOptions object", + input: { }, + expected: 0 }, + { desc: "a non-zero duration and default iteration count", + input: { duration: 1000 }, + expected: 1000 }, + { desc: "a non-zero duration and integral iteration count", + input: { duration: 1000, iterations: 7 }, + expected: 7000 }, + { desc: "a non-zero duration and fractional iteration count", + input: { duration: 1000, iterations: 2.5 }, + expected: 2500 }, + { desc: "an non-zero duration and infinite iteration count", + input: { duration: 1000, iterations: Infinity }, + expected: Infinity }, + { desc: "an non-zero duration and zero iteration count", + input: { duration: 1000, iterations: 0 }, + expected: 0 }, + { desc: "a zero duration and default iteration count", + input: { duration: 0 }, + expected: 0 }, + { desc: "a zero duration and fractional iteration count", + input: { duration: 0, iterations: 2.5 }, + expected: 0 }, + { desc: "a zero duration and infinite iteration count", + input: { duration: 0, iterations: Infinity }, + expected: 0 }, + { desc: "a zero duration and zero iteration count", + input: { duration: 0, iterations: 0 }, + expected: 0 }, + { desc: "an infinite duration and default iteration count", + input: { duration: Infinity }, + expected: Infinity }, + { desc: "an infinite duration and zero iteration count", + input: { duration: Infinity, iterations: 0 }, + expected: 0 }, + { desc: "an infinite duration and fractional iteration count", + input: { duration: Infinity, iterations: 2.5 }, + expected: Infinity }, + { desc: "an infinite duration and infinite iteration count", + input: { duration: Infinity, iterations: Infinity }, + expected: Infinity }, + { desc: "an infinite duration and zero iteration count", + input: { duration: Infinity, iterations: 0 }, + expected: 0 }, + { desc: "an invalid duration and default iteration count", + input: { duration: "cabbage" }, + expected: 0 }, + { desc: "a non-zero duration and invalid iteration count", + input: { duration: 1000, iterations: "cabbage" }, + expected: 1000 }, + { desc: "an invalid duration and invalid iteration count", + input: { duration: "cabbage", iterations: "cabbage" }, + expected: 0 } +]; + +gActiveDurationTests.forEach(function(stest) { + test(function(t) { + var effect = new KeyframeEffectReadOnly(target, + { left: ["10px", "20px"] }, + stest.input); + + assert_equals(effect.getComputedTiming().activeDuration, + stest.expected); + + }, "getComputedTiming().activeDuration for " + stest.desc); +}); + +var gEndTimeTests = [ + { desc: "an empty KeyframeEffectOptions object", + input: { }, + expected: 0 }, + { desc: "a non-zero duration and default iteration count", + input: { duration: 1000 }, + expected: 1000 }, + { desc: "a non-zero duration and non-default iteration count", + input: { duration: 1000, iterations: 2.5 }, + expected: 2500 }, + { desc: "a non-zero duration and non-zero delay", + input: { duration: 1000, delay: 1500 }, + expected: 2500 }, + { desc: "a non-zero duration, non-zero delay and non-default iteration", + input: { duration: 1000, delay: 1500, iterations: 2 }, + expected: 3500 }, + { desc: "an infinite iteration count", + input: { duration: 1000, iterations: Infinity }, + expected: Infinity }, + { desc: "an infinite duration", + input: { duration: Infinity, iterations: 10 }, + expected: Infinity }, + { desc: "an infinite duration and delay", + input: { duration: Infinity, iterations: 10, delay: 1000 }, + expected: Infinity }, + { desc: "an infinite duration and negative delay", + input: { duration: Infinity, iterations: 10, delay: -1000 }, + expected: Infinity }, + { desc: "an non-zero duration and negative delay", + input: { duration: 1000, iterations: 2, delay: -1000 }, + expected: 1000 }, + { desc: "an non-zero duration and negative delay greater than active " + + "duration", + input: { duration: 1000, iterations: 2, delay: -3000 }, + expected: -1000 }, + { desc: "a zero duration and negative delay", + input: { duration: 0, iterations: 2, delay: -1000 }, + expected: -1000 } +]; + +gEndTimeTests.forEach(function(stest) { + test(function(t) { + var effect = new KeyframeEffectReadOnly(target, + { left: ["10px", "20px"] }, + stest.input); + + assert_equals(effect.getComputedTiming().endTime, + stest.expected); + + }, "getComputedTiming().endTime for " + stest.desc); +}); + done(); diff --git a/toolkit/components/extensions/Extension.jsm b/toolkit/components/extensions/Extension.jsm index 55c92253aaab..724bdad6ce3e 100644 --- a/toolkit/components/extensions/Extension.jsm +++ b/toolkit/components/extensions/Extension.jsm @@ -1214,4 +1214,3 @@ Extension.prototype = extend(Object.create(ExtensionData.prototype), { return this.localize(this.manifest.name); }, }); - diff --git a/toolkit/components/extensions/ExtensionContent.jsm b/toolkit/components/extensions/ExtensionContent.jsm index e66ca20ae0f0..fd83aa29c612 100644 --- a/toolkit/components/extensions/ExtensionContent.jsm +++ b/toolkit/components/extensions/ExtensionContent.jsm @@ -118,6 +118,10 @@ var api = context => { getMessage: function(messageName, substitutions) { return context.extension.localizeMessage(messageName, substitutions); }, + + getUILanguage: function() { + return context.extension.localeData.uiLocale; + }, }, }; }; diff --git a/toolkit/components/extensions/ExtensionUtils.jsm b/toolkit/components/extensions/ExtensionUtils.jsm index d2bb97d11369..6cb101d93804 100644 --- a/toolkit/components/extensions/ExtensionUtils.jsm +++ b/toolkit/components/extensions/ExtensionUtils.jsm @@ -333,9 +333,7 @@ LocaleData.prototype = { // Check for certain pre-defined messages. if (message == "@@ui_locale") { - // Return the browser locale, but convert it to a Chrome-style - // locale code. - return Locale.getLocale().replace(/-/g, "_"); + return this.uiLocale; } else if (message.startsWith("@@bidi_")) { let registry = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry); let rtl = registry.isLocaleRTL("global"); @@ -426,6 +424,13 @@ LocaleData.prototype = { this.messages.set(locale, result); return result; }, + + get uiLocale() { + // Return the browser locale, but convert it to a Chrome-style + // locale code. + return Locale.getLocale().replace(/-/g, "_"); + }, + }; // This is a generic class for managing event listeners. Example usage: diff --git a/toolkit/components/extensions/ext-i18n.js b/toolkit/components/extensions/ext-i18n.js index 141ea1692d2d..61ce563acb2f 100644 --- a/toolkit/components/extensions/ext-i18n.js +++ b/toolkit/components/extensions/ext-i18n.js @@ -6,6 +6,10 @@ extensions.registerSchemaAPI("i18n", null, (extension, context) => { getMessage: function(messageName, substitutions) { return extension.localizeMessage(messageName, substitutions); }, + + getUILanguage: function() { + return extension.localeData.uiLocale; + }, }, }; }); diff --git a/toolkit/components/extensions/schemas/i18n.json b/toolkit/components/extensions/schemas/i18n.json index fb87db8ed39d..d43d3cdbda87 100644 --- a/toolkit/components/extensions/schemas/i18n.json +++ b/toolkit/components/extensions/schemas/i18n.json @@ -68,7 +68,6 @@ }, { "name": "getUILanguage", - "unsupported": true, "type": "function", "description": "Gets the browser UI language of the browser. This is different from $(ref:i18n.getAcceptLanguages) which returns the preferred user languages.", "parameters": [], diff --git a/toolkit/components/extensions/test/mochitest/test_ext_i18n.html b/toolkit/components/extensions/test/mochitest/test_ext_i18n.html index 50e9ed97ab5c..844bdd0b361d 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_i18n.html +++ b/toolkit/components/extensions/test/mochitest/test_ext_i18n.html @@ -14,6 +14,8 @@ diff --git a/toolkit/crashreporter/nsExceptionHandler.cpp b/toolkit/crashreporter/nsExceptionHandler.cpp index 8b6eaf4dd49a..9686c98a09d8 100644 --- a/toolkit/crashreporter/nsExceptionHandler.cpp +++ b/toolkit/crashreporter/nsExceptionHandler.cpp @@ -13,6 +13,7 @@ #include "mozilla/unused.h" #include "mozilla/Snprintf.h" #include "mozilla/SyncRunnable.h" +#include "mozilla/TimeStamp.h" #include "nsThreadUtils.h" #include "nsXULAppAPI.h" @@ -87,6 +88,7 @@ using mozilla::InjectCrashRunnable; #include #include +#include "mozilla/double-conversion.h" #include "mozilla/IOInterposer.h" #include "mozilla/mozalloc_oom.h" #include "mozilla/WindowsDllBlocklist.h" @@ -411,6 +413,57 @@ typedef struct { static std::vector library_mappings; typedef std::map MappingMap; #endif +} + +// Format a non-negative double to a string, without using C-library functions, +// which need to be avoided (.e.g. bug 1240160, comment 10). Leave the utility +// non-file static so that we can gtest it. Return false if we failed to +// get the formatting done correctly. +bool SimpleNoCLibDtoA(double aValue, char* aBuffer, int aBufferLength) +{ + // aBufferLength is the size of the buffer. Be paranoid. + aBuffer[aBufferLength-1] = '\0'; + + if (aValue < 0) { + return false; + } + + int length, point, i; + bool sign; + bool ok = true; + double_conversion::DoubleToStringConverter::DoubleToAscii( + aValue, + double_conversion::DoubleToStringConverter::SHORTEST, + 8, + aBuffer, + aBufferLength, + &sign, + &length, + &point); + + // length does not account for the 0 terminator. + if (length > point && (length+1) < (aBufferLength-1)) { + // We have to insert a decimal point. Not worried about adding a leading zero + // in the < 1 (point == 0) case. + aBuffer[length+1] = '\0'; + for (i=length; i>point; i-=1) { + aBuffer[i] = aBuffer[i-1]; + } + aBuffer[i] = '.'; // Not worried about locales + } else if (length < point) { + // Trailing zeros scenario + for (i=length; i= aBufferLength-2) { + ok = false; + } + aBuffer[i] = '0'; + } + aBuffer[i] = '\0'; + } + return ok; +} + +namespace CrashReporter { #ifdef XP_LINUX inline void @@ -754,6 +807,12 @@ bool MinidumpCallback( WriteString(lastCrashFile, crashTimeString); } + bool ignored = false; + double uptimeTS = (TimeStamp::NowLoRes()- + TimeStamp::ProcessCreation(ignored)).ToSecondsSigDigits(); + char uptimeTSString[64]; + SimpleNoCLibDtoA(uptimeTS, uptimeTSString, sizeof(uptimeTSString)); + // Write crash event file. // Minidump IDs are UUIDs (36) + NULL. @@ -805,6 +864,8 @@ bool MinidumpCallback( apiData.WriteBuffer(crashReporterAPIData->get(), crashReporterAPIData->Length()); } WriteAnnotation(apiData, "CrashTime", crashTimeString); + WriteAnnotation(apiData, "UptimeTS", uptimeTSString); + if (timeSinceLastCrash != 0) { WriteAnnotation(apiData, "SecondsSinceLastCrash", timeSinceLastCrashString); @@ -2594,6 +2655,16 @@ WriteExtraData(nsIFile* extraFile, WriteAnnotation(fd, nsDependentCString("CrashTime"), nsDependentCString(crashTimeString)); + + bool ignored = false; + double uptimeTS = (TimeStamp::NowLoRes()- + TimeStamp::ProcessCreation(ignored)).ToSecondsSigDigits(); + char uptimeTSString[64]; + SimpleNoCLibDtoA(uptimeTS, uptimeTSString, sizeof(uptimeTSString)); + + WriteAnnotation(fd, + nsDependentCString("UptimeTS"), + nsDependentCString(uptimeTSString)); } PR_Close(fd); diff --git a/toolkit/mozapps/extensions/internal/XPIProviderUtils.js b/toolkit/mozapps/extensions/internal/XPIProviderUtils.js index f5ab1a11fa8d..cdaf2b299bd2 100644 --- a/toolkit/mozapps/extensions/internal/XPIProviderUtils.js +++ b/toolkit/mozapps/extensions/internal/XPIProviderUtils.js @@ -1723,7 +1723,10 @@ this.XPIDatabaseReconcile = { logger.warn("Disabling foreign installed add-on " + aNewAddon.id + " in " + aInstallLocation.name); aNewAddon.userDisabled = true; - aNewAddon.seen = false; + + // If we don't have an old app version then this is a new profile in + // which case just mark any sideloaded add-ons as already seen. + aNewAddon.seen = !aOldAppVersion; } } diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_seen_newprofile.js b/toolkit/mozapps/extensions/test/xpcshell/test_seen_newprofile.js new file mode 100644 index 000000000000..43ee18594e02 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/test_seen_newprofile.js @@ -0,0 +1,41 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +const ID = "bootstrap1@tests.mozilla.org"; + +Services.prefs.setIntPref("extensions.enabledScopes", + AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_SYSTEM); + +createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2"); + +BootstrapMonitor.init(); + +const globalDir = gProfD.clone(); +globalDir.append("extensions2"); +globalDir.append(gAppInfo.ID); +registerDirectory("XRESysSExtPD", globalDir.parent); +const profileDir = gProfD.clone(); +profileDir.append("extensions"); + +// By default disable add-ons from the system +Services.prefs.setIntPref("extensions.autoDisableScopes", AddonManager.SCOPE_SYSTEM); + +// When new add-ons already exist in a system location when starting with a new +// profile they should be marked as already seen. +add_task(function*() { + manuallyInstall(do_get_addon("test_bootstrap1_1"), globalDir, ID); + + startupManager(); + + let addon = yield promiseAddonByID(ID); + do_check_true(addon.foreignInstall); + do_check_true(addon.seen); + do_check_true(addon.userDisabled); + do_check_false(addon.isActive); + + BootstrapMonitor.checkAddonInstalled(ID); + BootstrapMonitor.checkAddonNotStarted(ID); + + yield promiseShutdownManager(); +}); diff --git a/toolkit/mozapps/extensions/test/xpcshell/xpcshell-shared.ini b/toolkit/mozapps/extensions/test/xpcshell/xpcshell-shared.ini index c1493d439257..3c72e29960ca 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell-shared.ini +++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell-shared.ini @@ -285,6 +285,7 @@ skip-if = os == "android" run-sequentially = Uses hardcoded ports in xpi files. [test_json_updatecheck.js] [test_seen.js] +[test_seen_newprofile.js] [test_updateid.js] # Bug 676992: test consistently hangs on Android skip-if = os == "android" diff --git a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini index 8854134ad3aa..c713e8f27bb0 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini +++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini @@ -32,4 +32,5 @@ skip-if = appname != "firefox" [test_temporary.js] [test_proxy.js] + [include:xpcshell-shared.ini] diff --git a/uriloader/exthandler/mac/nsOSHelperAppService.mm b/uriloader/exthandler/mac/nsOSHelperAppService.mm index 5f030cc4cf92..0367e49bee4e 100644 --- a/uriloader/exthandler/mac/nsOSHelperAppService.mm +++ b/uriloader/exthandler/mac/nsOSHelperAppService.mm @@ -329,7 +329,7 @@ nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType, if (!aMIMEType.IsEmpty()) { CFURLRef appURL = NULL; // CFStringCreateWithCString() can fail even if we're not out of memory -- - // for example if the 'cStr' parameter is something very wierd (like "ÿÿ~" + // for example if the 'cStr' parameter is something very weird (like "ÿÿ~" // aka "\xFF\xFF~"), or possibly if it can't be interpreted as using what's // specified in the 'encoding' parameter. See bug 548719. cfMIMEType = ::CFStringCreateWithCString(NULL, flatType.get(), diff --git a/widget/cocoa/nsChildView.h b/widget/cocoa/nsChildView.h index ffe3aef394db..e41f2ef5c7bd 100644 --- a/widget/cocoa/nsChildView.h +++ b/widget/cocoa/nsChildView.h @@ -539,7 +539,9 @@ public: return nsCocoaUtils::DevPixelsToCocoaPoints(aRect, BackingScaleFactor()); } - already_AddRefed StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion) override; + already_AddRefed + StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion, + mozilla::layers::BufferMode* aBufferMode) override; void EndRemoteDrawing() override; void CleanupRemoteDrawing() override; bool InitCompositor(mozilla::layers::Compositor* aCompositor) override; diff --git a/widget/cocoa/nsChildView.mm b/widget/cocoa/nsChildView.mm index 56b45cbd27d1..76af2e1ae4c9 100644 --- a/widget/cocoa/nsChildView.mm +++ b/widget/cocoa/nsChildView.mm @@ -2635,7 +2635,8 @@ nsChildView::SwipeFinished() } already_AddRefed -nsChildView::StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion) +nsChildView::StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion, + BufferMode* aBufferMode) { // should have created the GLPresenter in InitCompositor. MOZ_ASSERT(mGLPresenter); diff --git a/widget/cocoa/nsMenuUtilsX.mm b/widget/cocoa/nsMenuUtilsX.mm index b3108d9a0804..db6471712794 100644 --- a/widget/cocoa/nsMenuUtilsX.mm +++ b/widget/cocoa/nsMenuUtilsX.mm @@ -116,7 +116,7 @@ NSMenuItem* nsMenuUtilsX::GetStandardEditMenuItem() NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; // In principle we should be able to allocate this once and then always - // return the same object. But wierd interactions happen between native + // return the same object. But weird interactions happen between native // app-modal dialogs and Gecko-modal dialogs that open above them. So what // we return here isn't always released before it needs to be added to // another menu. See bmo bug 468393. diff --git a/widget/gonk/nsScreenManagerGonk.cpp b/widget/gonk/nsScreenManagerGonk.cpp index 976c7fb26d7a..828b6de08d21 100644 --- a/widget/gonk/nsScreenManagerGonk.cpp +++ b/widget/gonk/nsScreenManagerGonk.cpp @@ -754,6 +754,9 @@ NS_IMPL_ISUPPORTS(nsScreenManagerGonk, nsIScreenManager) nsScreenManagerGonk::nsScreenManagerGonk() : mInitialized(false) +#if ANDROID_VERSION >= 19 + , mDisplayEnabled(false) +#endif { } @@ -816,9 +819,16 @@ nsScreenManagerGonk::Initialize() void nsScreenManagerGonk::DisplayEnabled(bool aEnabled) { + MOZ_ASSERT(NS_IsMainThread()); + #if ANDROID_VERSION >= 19 + /* Bug 1244044 + * This function could be called before |mCompositorVsyncScheduler| is set. + * To avoid this issue, keep the value stored in |mDisplayEnabled|. + */ + mDisplayEnabled = aEnabled; if (mCompositorVsyncScheduler) { - mCompositorVsyncScheduler->SetDisplay(aEnabled); + mCompositorVsyncScheduler->SetDisplay(mDisplayEnabled); } #endif @@ -1063,6 +1073,8 @@ nsScreenManagerGonk::SetCompositorVsyncScheduler(mozilla::layers::CompositorVsyn // We assume on b2g that there is only 1 CompositorParent MOZ_ASSERT(mCompositorVsyncScheduler == nullptr); + MOZ_ASSERT(aObserver); mCompositorVsyncScheduler = aObserver; + mCompositorVsyncScheduler->SetDisplay(mDisplayEnabled); } #endif diff --git a/widget/gonk/nsScreenManagerGonk.h b/widget/gonk/nsScreenManagerGonk.h index 3947ea98eaa1..23a2f24b4122 100644 --- a/widget/gonk/nsScreenManagerGonk.h +++ b/widget/gonk/nsScreenManagerGonk.h @@ -220,6 +220,7 @@ protected: RefPtr mScreenOffEvent; #if ANDROID_VERSION >= 19 + bool mDisplayEnabled; RefPtr mCompositorVsyncScheduler; #endif }; diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp index 56d963df3aa8..4869b1710088 100644 --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -2225,7 +2225,8 @@ nsWindow::OnExposeEvent(cairo_t *cr) return TRUE; } - RefPtr dt = GetDrawTarget(region); + BufferMode layerBuffering = BufferMode::BUFFERED; + RefPtr dt = GetDrawTarget(region, &layerBuffering); if (!dt) { return FALSE; } @@ -2245,7 +2246,6 @@ nsWindow::OnExposeEvent(cairo_t *cr) gfxUtils::ClipToRegion(dt, region.ToUnknownRegion()); } - BufferMode layerBuffering; if (shaped) { // The double buffering is done here to extract the shape mask. // (The shape mask won't be necessary when a visual with an alpha @@ -2254,16 +2254,6 @@ nsWindow::OnExposeEvent(cairo_t *cr) RefPtr destDT = dt->CreateSimilarDrawTarget(boundsRect.Size(), SurfaceFormat::B8G8R8A8); ctx = new gfxContext(destDT, boundsRect.TopLeft()); } else { -#ifdef MOZ_HAVE_SHMIMAGE - if (nsShmImage::UseShm()) { - // We're using an xshm mapping as a back buffer. - layerBuffering = BufferMode::BUFFER_NONE; - } else -#endif // MOZ_HAVE_SHMIMAGE - { - // Get the layer manager to do double buffering (if necessary). - layerBuffering = BufferMode::BUFFERED; - } ctx = new gfxContext(dt); } @@ -6455,7 +6445,7 @@ nsWindow::GetSurfaceForGdkDrawable(GdkDrawable* aDrawable, #endif already_AddRefed -nsWindow::GetDrawTarget(const LayoutDeviceIntRegion& aRegion) +nsWindow::GetDrawTarget(const LayoutDeviceIntRegion& aRegion, BufferMode* aBufferMode) { if (!mGdkWindow) { return nullptr; @@ -6474,12 +6464,14 @@ nsWindow::GetDrawTarget(const LayoutDeviceIntRegion& aRegion) if (nsShmImage::UseShm()) { dt = nsShmImage::EnsureShmImage(size, mXDisplay, mXVisual, mXDepth, mShmImage); + *aBufferMode = BufferMode::BUFFER_NONE; } # endif // MOZ_HAVE_SHMIMAGE if (!dt) { RefPtr surf = new gfxXlibSurface(mXDisplay, mXWindow, mXVisual, size.ToUnknownSize()); if (!surf->CairoStatus()) { dt = gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(surf.get(), surf->GetSize()); + *aBufferMode = BufferMode::BUFFERED; } } #endif // MOZ_X11 @@ -6488,9 +6480,9 @@ nsWindow::GetDrawTarget(const LayoutDeviceIntRegion& aRegion) } already_AddRefed -nsWindow::StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion) +nsWindow::StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion, BufferMode* aBufferMode) { - return GetDrawTarget(aInvalidRegion); + return GetDrawTarget(aInvalidRegion, aBufferMode); } void diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h index aa3c0a69ef86..aa3b7b3d9c3c 100644 --- a/widget/gtk/nsWindow.h +++ b/widget/gtk/nsWindow.h @@ -8,8 +8,6 @@ #ifndef __nsWindow_h__ #define __nsWindow_h__ -#include "mozilla/ipc/SharedMemorySysV.h" - #include "nsAutoPtr.h" #include "mozcontainer.h" @@ -27,6 +25,8 @@ #include #endif /* MOZ_X11 */ +#include "nsShmImage.h" + #ifdef ACCESSIBILITY #include "mozilla/a11y/Accessible.h" #endif @@ -64,10 +64,6 @@ extern PRLogModuleInfo *gWidgetDrawLog; class gfxASurface; class gfxPattern; class nsPluginNativeWindowGtk; -#if defined(MOZ_X11) && defined(MOZ_HAVE_SHAREDMEMORYSYSV) -# define MOZ_HAVE_SHMIMAGE -class nsShmImage; -#endif namespace mozilla { class TimeStamp; @@ -220,7 +216,8 @@ public: #endif virtual already_AddRefed - StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion) override; + StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion, + mozilla::layers::BufferMode* aBufferMode) override; virtual void EndRemoteDrawingInRegion(mozilla::gfx::DrawTarget* aDrawTarget, LayoutDeviceIntRegion& aInvalidRegion) override; @@ -313,7 +310,9 @@ public: virtual nsresult ConfigureChildren(const nsTArray& aConfigurations) override; nsresult UpdateTranslucentWindowAlphaInternal(const nsIntRect& aRect, uint8_t* aAlphas, int32_t aStride); - virtual already_AddRefed GetDrawTarget(const LayoutDeviceIntRegion& aRegion); + + already_AddRefed GetDrawTarget(const LayoutDeviceIntRegion& aRegion, + mozilla::layers::BufferMode* aBufferMode); #if (MOZ_WIDGET_GTK == 2) static already_AddRefed GetSurfaceForGdkDrawable(GdkDrawable* aDrawable, diff --git a/widget/nsIBaseWindow.idl b/widget/nsIBaseWindow.idl index 88160bce0a3c..24289a70b38a 100644 --- a/widget/nsIBaseWindow.idl +++ b/widget/nsIBaseWindow.idl @@ -91,6 +91,12 @@ interface nsIBaseWindow : nsISupports */ void setPosition(in long x, in long y); + /* + Ditto, with arguments in global desktop pixels rather than (potentially + ambiguous) device pixels + */ + void setPositionDesktopPix(in long x, in long y); + /* Gets the current x and y coordinates of the control. This is relatie to the parent window. diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h index 7c99fc42bc2a..0d8caff3f646 100644 --- a/widget/nsIWidget.h +++ b/widget/nsIWidget.h @@ -1287,9 +1287,13 @@ class nsIWidget : public nsISupports { * * Called by BasicCompositor on the compositor thread for OMTC drawing * before each composition. + * + * The window may specify its buffer mode. If unspecified, it is assumed + * to require double-buffering. */ virtual already_AddRefed StartRemoteDrawing() = 0; - virtual already_AddRefed StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion) { + virtual already_AddRefed StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion, + mozilla::layers::BufferMode* aBufferMode) { return StartRemoteDrawing(); } diff --git a/widget/nsShmImage.cpp b/widget/nsShmImage.cpp index 4f097d4812e6..964e7a7d0be2 100644 --- a/widget/nsShmImage.cpp +++ b/widget/nsShmImage.cpp @@ -17,6 +17,14 @@ #endif #ifdef MOZ_HAVE_SHMIMAGE +#include "mozilla/X11Util.h" + +#include "mozilla/ipc/SharedMemory.h" + +#include +#include +#include +#include using namespace mozilla::ipc; using namespace mozilla::gfx; @@ -45,92 +53,143 @@ TrapShmError(Display* aDisplay, XErrorEvent* aEvent) } #endif -already_AddRefed -nsShmImage::Create(const LayoutDeviceIntSize& aSize, - Display* aDisplay, Visual* aVisual, unsigned int aDepth) +bool +nsShmImage::CreateShmSegment() { - RefPtr shm = new nsShmImage(); - shm->mDisplay = aDisplay; - shm->mImage = XShmCreateImage(aDisplay, aVisual, aDepth, - ZPixmap, nullptr, - &(shm->mInfo), - aSize.width, aSize.height); - if (!shm->mImage) { - return nullptr; - } + if (!mImage) { + return false; + } - size_t size = SharedMemory::PageAlignedSize( - shm->mImage->bytes_per_line * shm->mImage->height); - shm->mSegment = new SharedMemorySysV(); - if (!shm->mSegment->Create(size) || !shm->mSegment->Map(size)) { - return nullptr; - } + size_t size = SharedMemory::PageAlignedSize(mImage->bytes_per_line * mImage->height); - shm->mInfo.shmid = shm->mSegment->GetHandle(); - shm->mInfo.shmaddr = - shm->mImage->data = static_cast(shm->mSegment->memory()); - shm->mInfo.readOnly = False; + mInfo.shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0600); + if (mInfo.shmid == -1) { + return false; + } -#if defined(MOZ_WIDGET_GTK) - gShmError = 0; - XErrorHandler previousHandler = XSetErrorHandler(TrapShmError); - Status attachOk = XShmAttach(aDisplay, &shm->mInfo); - XSync(aDisplay, False); - XSetErrorHandler(previousHandler); - if (gShmError) { - attachOk = 0; - } -#elif defined(MOZ_WIDGET_QT) - Status attachOk = XShmAttach(aDisplay, &shm->mInfo); + mInfo.shmaddr = (char *)shmat(mInfo.shmid, nullptr, 0); + if (mInfo.shmaddr == (void *)-1) { + nsPrintfCString warning("shmat(): %s (%d)\n", strerror(errno), errno); + NS_WARNING(warning.get()); + return false; + } + + // Mark the handle as deleted so that, should this process go away, the + // segment is cleaned up. + shmctl(mInfo.shmid, IPC_RMID, 0); + +#ifdef DEBUG + struct shmid_ds info; + if (shmctl(mInfo.shmid, IPC_STAT, &info) < 0) { + return false; + } + + MOZ_ASSERT(size <= info.shm_segsz, + "Segment doesn't have enough space!"); #endif - if (!attachOk) { - // Assume XShm isn't available, and don't attempt to use it - // again. - gShmAvailable = false; - return nullptr; - } + mInfo.readOnly = False; - shm->mXAttached = true; - shm->mSize = aSize; - switch (shm->mImage->depth) { - case 32: - if ((shm->mImage->red_mask == 0xff0000) && - (shm->mImage->green_mask == 0xff00) && - (shm->mImage->blue_mask == 0xff)) { - shm->mFormat = SurfaceFormat::B8G8R8A8; - memset(shm->mSegment->memory(), 0, size); - break; - } - goto unsupported; - case 24: - // Only xRGB is supported. - if ((shm->mImage->red_mask == 0xff0000) && - (shm->mImage->green_mask == 0xff00) && - (shm->mImage->blue_mask == 0xff)) { - shm->mFormat = SurfaceFormat::B8G8R8X8; - memset(shm->mSegment->memory(), 0xFF, size); - break; - } - goto unsupported; - case 16: - shm->mFormat = SurfaceFormat::R5G6B5_UINT16; - memset(shm->mSegment->memory(), 0, size); - break; - unsupported: - default: - NS_WARNING("Unsupported XShm Image format!"); - gShmAvailable = false; - return nullptr; + mImage->data = mInfo.shmaddr; + + return true; +} + +void +nsShmImage::DestroyShmSegment() +{ + if (mInfo.shmid != -1) { + shmdt(mInfo.shmaddr); + mInfo.shmid = -1; + } +} + +bool +nsShmImage::CreateImage(const LayoutDeviceIntSize& aSize, + Display* aDisplay, Visual* aVisual, unsigned int aDepth) +{ + mDisplay = aDisplay; + mImage = XShmCreateImage(aDisplay, aVisual, aDepth, + ZPixmap, nullptr, + &mInfo, + aSize.width, aSize.height); + if (!mImage || !CreateShmSegment()) { + return false; + } + +#if defined(MOZ_WIDGET_GTK) + gShmError = 0; + XErrorHandler previousHandler = XSetErrorHandler(TrapShmError); + Status attachOk = XShmAttach(aDisplay, &mInfo); + XSync(aDisplay, False); + XSetErrorHandler(previousHandler); + if (gShmError) { + attachOk = 0; + } +#elif defined(MOZ_WIDGET_QT) + Status attachOk = XShmAttach(aDisplay, &mInfo); +#endif + + if (!attachOk) { + // Assume XShm isn't available, and don't attempt to use it + // again. + gShmAvailable = false; + return false; + } + + mXAttached = true; + mSize = aSize; + mFormat = SurfaceFormat::UNKNOWN; + switch (mImage->depth) { + case 32: + if ((mImage->red_mask == 0xff0000) && + (mImage->green_mask == 0xff00) && + (mImage->blue_mask == 0xff)) { + mFormat = SurfaceFormat::B8G8R8A8; + memset(mImage->data, 0, mImage->bytes_per_line * mImage->height); } - return shm.forget(); + break; + case 24: + // Only xRGB is supported. + if ((mImage->red_mask == 0xff0000) && + (mImage->green_mask == 0xff00) && + (mImage->blue_mask == 0xff)) { + mFormat = SurfaceFormat::B8G8R8X8; + memset(mImage->data, 0xFF, mImage->bytes_per_line * mImage->height); + } + break; + case 16: + mFormat = SurfaceFormat::R5G6B5_UINT16; + memset(mImage->data, 0, mImage->bytes_per_line * mImage->height); + break; + } + + if (mFormat == SurfaceFormat::UNKNOWN) { + NS_WARNING("Unsupported XShm Image format!"); + gShmAvailable = false; + return false; + } + + return true; +} + +nsShmImage::~nsShmImage() +{ + if (mImage) { + mozilla::FinishX(mDisplay); + if (mXAttached) { + XShmDetach(mDisplay, &mInfo); + } + XDestroyImage(mImage); + } + DestroyShmSegment(); } already_AddRefed nsShmImage::CreateDrawTarget() { return gfxPlatform::GetPlatform()->CreateDrawTargetForData( - static_cast(mSegment->memory()), + reinterpret_cast(mImage->data), mSize.ToUnknownSize(), mImage->bytes_per_line, mFormat); @@ -189,15 +248,18 @@ nsShmImage::EnsureShmImage(const LayoutDeviceIntSize& aSize, Display* aDisplay, Visual* aVisual, unsigned int aDepth, RefPtr& aImage) { - if (!aImage || aImage->Size() != aSize) { - // Because we XSync() after XShmAttach() to trap errors, we - // know that the X server has the old image's memory mapped - // into its address space, so it's OK to destroy the old image - // here even if there are outstanding Puts. The Detach is - // ordered after the Puts. - aImage = nsShmImage::Create(aSize, aDisplay, aVisual, aDepth); + if (!aImage || aImage->Size() != aSize) { + // Because we XSync() after XShmAttach() to trap errors, we + // know that the X server has the old image's memory mapped + // into its address space, so it's OK to destroy the old image + // here even if there are outstanding Puts. The Detach is + // ordered after the Puts. + aImage = new nsShmImage; + if (!aImage->CreateImage(aSize, aDisplay, aVisual, aDepth)) { + aImage = nullptr; } - return !aImage ? nullptr : aImage->CreateDrawTarget(); + } + return !aImage ? nullptr : aImage->CreateDrawTarget(); } -#endif // defined(MOZ_X11) && defined(MOZ_HAVE_SHAREDMEMORYSYSV) +#endif // MOZ_HAVE_SHMIMAGE diff --git a/widget/nsShmImage.h b/widget/nsShmImage.h index a0cd94a22ed1..27c9d23f5554 100644 --- a/widget/nsShmImage.h +++ b/widget/nsShmImage.h @@ -7,9 +7,7 @@ #ifndef __mozilla_widget_nsShmImage_h__ #define __mozilla_widget_nsShmImage_h__ -#include "mozilla/ipc/SharedMemorySysV.h" - -#if defined(MOZ_X11) && defined(MOZ_HAVE_SHAREDMEMORYSYSV) +#if defined(MOZ_X11) # define MOZ_HAVE_SHMIMAGE #endif @@ -19,9 +17,7 @@ #include "nsIWidget.h" #include "nsAutoPtr.h" -#include "mozilla/X11Util.h" #include -#include #include #ifdef MOZ_WIDGET_QT @@ -33,30 +29,13 @@ class nsShmImage { // bug 1168843, compositor thread may create shared memory instances that are destroyed by main thread on shutdown, so this must use thread-safe RC to avoid hitting assertion NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsShmImage) - typedef mozilla::ipc::SharedMemorySysV SharedMemorySysV; - public: static bool UseShm(); - static already_AddRefed - Create(const mozilla::LayoutDeviceIntSize& aSize, - Display* aDisplay, Visual* aVisual, unsigned int aDepth); static already_AddRefed EnsureShmImage(const mozilla::LayoutDeviceIntSize& aSize, Display* aDisplay, Visual* aVisual, unsigned int aDepth, RefPtr& aImage); -private: - ~nsShmImage() { - if (mImage) { - mozilla::FinishX(mDisplay); - if (mXAttached) { - XShmDetach(mDisplay, &mInfo); - } - XDestroyImage(mImage); - } - } - -public: already_AddRefed CreateDrawTarget(); #ifdef MOZ_WIDGET_GTK @@ -74,9 +53,16 @@ private: , mDisplay(nullptr) , mFormat(mozilla::gfx::SurfaceFormat::UNKNOWN) , mXAttached(false) - { mInfo.shmid = SharedMemorySysV::NULLHandle(); } + { mInfo.shmid = -1; } + + ~nsShmImage(); + + bool CreateShmSegment(); + void DestroyShmSegment(); + + bool CreateImage(const mozilla::LayoutDeviceIntSize& aSize, + Display* aDisplay, Visual* aVisual, unsigned int aDepth); - RefPtr mSegment; XImage* mImage; Display* mDisplay; XShmSegmentInfo mInfo; diff --git a/xpcom/base/CycleCollectedJSRuntime.cpp b/xpcom/base/CycleCollectedJSRuntime.cpp index 9db8a28976aa..d370d5322105 100644 --- a/xpcom/base/CycleCollectedJSRuntime.cpp +++ b/xpcom/base/CycleCollectedJSRuntime.cpp @@ -1557,6 +1557,7 @@ CycleCollectedJSRuntime::OnGC(JSGCStatus aStatus) switch (aStatus) { case JSGC_BEGIN: nsCycleCollector_prepareForGarbageCollection(); + mZonesWaitingForGC.Clear(); break; case JSGC_END: { #ifdef MOZ_CRASHREPORTER @@ -1599,3 +1600,16 @@ CycleCollectedJSRuntime::OnLargeAllocationFailure() CustomLargeAllocationFailureCallback(); AnnotateAndSetOutOfMemory(&mLargeAllocationFailureState, OOMState::Reported); } + +void +CycleCollectedJSRuntime::PrepareWaitingZonesForGC() +{ + if (mZonesWaitingForGC.Count() == 0) { + JS::PrepareForFullGC(Runtime()); + } else { + for (auto iter = mZonesWaitingForGC.Iter(); !iter.Done(); iter.Next()) { + JS::PrepareZoneForGC(iter.Get()->GetKey()); + } + mZonesWaitingForGC.Clear(); + } +} diff --git a/xpcom/base/CycleCollectedJSRuntime.h b/xpcom/base/CycleCollectedJSRuntime.h index 3cc3b763bfa1..a1e250325d9e 100644 --- a/xpcom/base/CycleCollectedJSRuntime.h +++ b/xpcom/base/CycleCollectedJSRuntime.h @@ -19,6 +19,7 @@ #include "nsDataHashtable.h" #include "nsHashKeys.h" #include "nsTArray.h" +#include "nsTHashtable.h" class nsCycleCollectionNoteRootCallback; class nsIException; @@ -334,6 +335,18 @@ public: // isn't one. static CycleCollectedJSRuntime* Get(); + // Add aZone to the set of zones waiting for a GC. + void AddZoneWaitingForGC(JS::Zone* aZone) + { + mZonesWaitingForGC.PutEntry(aZone); + } + + // Prepare any zones for GC that have been passed to AddZoneWaitingForGC() + // since the last GC or since the last call to PrepareWaitingZonesForGC(), + // whichever was most recent. If there were no such zones, prepare for a + // full GC. + void PrepareWaitingZonesForGC(); + // Storage for watching rejected promises waiting for some client to // consume their rejection. // We store values as `nsISupports` to avoid adding compile-time dependencies @@ -386,6 +399,8 @@ private: SegmentedVector, kSegmentSize, InfallibleAllocPolicy> mPreservedNurseryObjects; + + nsTHashtable> mZonesWaitingForGC; }; void TraceScriptHolder(nsISupports* aHolder, JSTracer* aTracer); diff --git a/xpcom/base/Logging.cpp b/xpcom/base/Logging.cpp index 2223f1b4bfbb..2d44d152ee02 100644 --- a/xpcom/base/Logging.cpp +++ b/xpcom/base/Logging.cpp @@ -12,12 +12,19 @@ #include "mozilla/FileUtils.h" #include "mozilla/Mutex.h" #include "mozilla/StaticPtr.h" +#include "mozilla/Snprintf.h" #include "nsClassHashtable.h" #include "nsDebug.h" #include "NSPRLogModulesParser.h" #include "prenv.h" #include "prprf.h" +#ifdef XP_WIN +#include +#else +#include +#include +#endif // NB: Initial amount determined by auditing the codebase for the total amount // of unique module names and padding up to the next power of 2. @@ -49,6 +56,15 @@ void log_print(const LogModule* aModule, va_end(ap); } +int log_pid() +{ +#ifdef XP_WIN + return _getpid(); +#else + return getpid(); +#endif +} + } LogLevel @@ -126,6 +142,18 @@ public: const char* logFile = PR_GetEnv("NSPR_LOG_FILE"); if (logFile && logFile[0]) { + static const char kPIDToken[] = "%PID"; + const char* pidTokenPtr = strstr(logFile, kPIDToken); + char buf[2048]; + if (pidTokenPtr && + snprintf_literal(buf, "%.*s%d%s", + static_cast(pidTokenPtr - logFile), logFile, + detail::log_pid(), + pidTokenPtr + strlen(kPIDToken)) > 0) + { + logFile = buf; + } + mOutFile = fopen(logFile, shouldAppend ? "a" : "w"); } } diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index 374e5daaab9f..d284e59fe5c8 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -3265,9 +3265,15 @@ nsCycleCollector::CollectWhite() if (pinfo->mColor == white && pinfo->mParticipant) { if (pinfo->IsGrayJS()) { ++numWhiteGCed; + JS::Zone* zone; if (MOZ_UNLIKELY(pinfo->mParticipant == zoneParticipant)) { ++numWhiteJSZones; + zone = static_cast(pinfo->mPointer); + } else { + JS::GCCellPtr ptr(pinfo->mPointer, js::GCThingTraceKind(pinfo->mPointer)); + zone = JS::GetTenuredGCThingZone(ptr); } + mJSRuntime->AddZoneWaitingForGC(zone); } else { whiteNodes.InfallibleAppend(pinfo); pinfo->mParticipant->Root(pinfo->mPointer); diff --git a/xpcom/ds/StickyTimeDuration.h b/xpcom/ds/StickyTimeDuration.h index 750e813ea849..39a887dbce23 100644 --- a/xpcom/ds/StickyTimeDuration.h +++ b/xpcom/ds/StickyTimeDuration.h @@ -159,7 +159,7 @@ StickyTimeDurationValueCalculator::Multiply(int64_t aA, // return -Forever if the signs differ, or +Forever otherwise. if (aA == INT64_MAX || aA == INT64_MIN || aB == INT64_MAX || aB == INT64_MIN) { - return (aA >= 0) ^ (aB >= 0) ? INT64_MAX : INT64_MIN; + return (aA >= 0) ^ (aB >= 0) ? INT64_MIN : INT64_MAX; } return aA * aB; @@ -177,7 +177,7 @@ StickyTimeDurationValueCalculator::Multiply(int64_t aA, double aB) // +/-Forever or +/-Infinity, then return -Forever if the signs differ, // or +Forever otherwise. if (aA == INT64_MAX || aA == INT64_MIN || IsInfinite(aB)) { - return (aA >= 0) ^ (aB >= 0.0) ? INT64_MAX : INT64_MIN; + return (aA >= 0) ^ (aB >= 0.0) ? INT64_MIN : INT64_MAX; } return aA * aB; diff --git a/xpfe/appshell/nsChromeTreeOwner.cpp b/xpfe/appshell/nsChromeTreeOwner.cpp index 969012028e7c..b5182535a7ee 100644 --- a/xpfe/appshell/nsChromeTreeOwner.cpp +++ b/xpfe/appshell/nsChromeTreeOwner.cpp @@ -388,6 +388,12 @@ NS_IMETHODIMP nsChromeTreeOwner::GetDevicePixelsPerDesktopPixel(double *aScale) return mXULWindow->GetDevicePixelsPerDesktopPixel(aScale); } +NS_IMETHODIMP nsChromeTreeOwner::SetPositionDesktopPix(int32_t x, int32_t y) +{ + NS_ENSURE_STATE(mXULWindow); + return mXULWindow->SetPositionDesktopPix(x, y); +} + NS_IMETHODIMP nsChromeTreeOwner::SetPosition(int32_t x, int32_t y) { NS_ENSURE_STATE(mXULWindow); diff --git a/xpfe/appshell/nsContentTreeOwner.cpp b/xpfe/appshell/nsContentTreeOwner.cpp index 522b1d5bf977..b7c7aee81e31 100644 --- a/xpfe/appshell/nsContentTreeOwner.cpp +++ b/xpfe/appshell/nsContentTreeOwner.cpp @@ -628,6 +628,12 @@ NS_IMETHODIMP nsContentTreeOwner::GetDevicePixelsPerDesktopPixel(double* aScale) return mXULWindow->GetDevicePixelsPerDesktopPixel(aScale); } +NS_IMETHODIMP nsContentTreeOwner::SetPositionDesktopPix(int32_t aX, int32_t aY) +{ + NS_ENSURE_STATE(mXULWindow); + return mXULWindow->SetPositionDesktopPix(aX, aY); +} + NS_IMETHODIMP nsContentTreeOwner::SetPosition(int32_t aX, int32_t aY) { NS_ENSURE_STATE(mXULWindow); diff --git a/xpfe/appshell/nsXULWindow.cpp b/xpfe/appshell/nsXULWindow.cpp index d38dd445fcf5..650c454ea5ca 100644 --- a/xpfe/appshell/nsXULWindow.cpp +++ b/xpfe/appshell/nsXULWindow.cpp @@ -577,51 +577,9 @@ NS_IMETHODIMP nsXULWindow::GetUnscaledDevicePixelsPerCSSPixel(double *aScale) return NS_OK; } -DesktopToLayoutDeviceScale -nsXULWindow::GetScaleForDestinationPosition(int32_t aX, int32_t aY) +NS_IMETHODIMP nsXULWindow::SetPositionDesktopPix(int32_t aX, int32_t aY) { - DesktopToLayoutDeviceScale scale(nsIWidget::DefaultScaleOverride()); - if (scale.scale <= 0.0) { - // The destination monitor may have the different dpi from the source. - nsCOMPtr screenMgr(do_GetService( - "@mozilla.org/gfx/screenmanager;1")); - if (screenMgr) { - int32_t width, height; - // Use current size, converted to desktop pixels - GetSize(&width, &height); - DesktopToLayoutDeviceScale curr = mWindow->GetDesktopToDeviceScale(); - width /= curr.scale; - height /= curr.scale; - width = std::max(1, width); - height = std::max(1, height); - nsCOMPtr screen; - screenMgr->ScreenForRect(aX, aY, width, height, - getter_AddRefs(screen)); - if (screen) { - double contentsScaleFactor; - if (NS_SUCCEEDED(screen->GetContentsScaleFactor( - &contentsScaleFactor))) { - scale = DesktopToLayoutDeviceScale(contentsScaleFactor); - } else { - // Fallback to the scale from the widget. - scale = mWindow->GetDesktopToDeviceScale(); - } - } - } else { - // this fallback should never actually be needed - scale = mWindow->GetDesktopToDeviceScale(); - } - } - return scale; -} - -NS_IMETHODIMP nsXULWindow::SetPosition(int32_t aX, int32_t aY) -{ - // Don't reset the window's size mode here - platforms that don't want to move - // maximized windows should reset it in their respective Move implementation. - DesktopToLayoutDeviceScale scale = GetScaleForDestinationPosition(aX, aY); - DesktopPoint pos = LayoutDeviceIntPoint(aX, aY) / scale; - nsresult rv = mWindow->Move(pos.x, pos.y); + nsresult rv = mWindow->Move(aX, aY); NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); if (!mChromeLoaded) { // If we're called before the chrome is loaded someone obviously wants this @@ -634,6 +592,17 @@ NS_IMETHODIMP nsXULWindow::SetPosition(int32_t aX, int32_t aY) return NS_OK; } +// The parameters here are device pixels; do the best we can to convert to +// desktop px, using the window's current scale factor (if available). +NS_IMETHODIMP nsXULWindow::SetPosition(int32_t aX, int32_t aY) +{ + // Don't reset the window's size mode here - platforms that don't want to move + // maximized windows should reset it in their respective Move implementation. + DesktopToLayoutDeviceScale currScale = mWindow->GetDesktopToDeviceScale(); + DesktopPoint pos = LayoutDeviceIntPoint(aX, aY) / currScale; + return SetPositionDesktopPix(pos.x, pos.y); +} + NS_IMETHODIMP nsXULWindow::GetPosition(int32_t* aX, int32_t* aY) { return GetPositionAndSize(aX, aY, nullptr, nullptr); @@ -1190,10 +1159,7 @@ bool nsXULWindow::LoadPositionFromXUL() } mWindow->ConstrainPosition(false, &specX, &specY); if (specX != currX || specY != currY) { - DesktopToLayoutDeviceScale destScale = - GetScaleForDestinationPosition(specX, specY); - LayoutDevicePoint devPos = DesktopIntPoint(specX, specY) * destScale; - SetPosition(devPos.x, devPos.y); + SetPositionDesktopPix(specX, specY); } return gotPosition; diff --git a/xpfe/appshell/nsXULWindow.h b/xpfe/appshell/nsXULWindow.h index 87f01d2d9887..3d503ad14bfb 100644 --- a/xpfe/appshell/nsXULWindow.h +++ b/xpfe/appshell/nsXULWindow.h @@ -90,9 +90,6 @@ protected: NS_IMETHOD EnsurePrompter(); NS_IMETHOD EnsureAuthPrompter(); - mozilla::DesktopToLayoutDeviceScale - GetScaleForDestinationPosition(int32_t aX, int32_t aY); - void OnChromeLoaded(); void StaggerPosition(int32_t &aRequestedX, int32_t &aRequestedY, int32_t aSpecWidth, int32_t aSpecHeight);