diff --git a/accessible/src/base/AccGroupInfo.cpp b/accessible/src/base/AccGroupInfo.cpp index 586d483bb49..14c7fccf646 100644 --- a/accessible/src/base/AccGroupInfo.cpp +++ b/accessible/src/base/AccGroupInfo.cpp @@ -11,14 +11,20 @@ using namespace mozilla::a11y; AccGroupInfo::AccGroupInfo(Accessible* aItem, role aRole) : - mPosInSet(0), mSetSize(0), mParent(nullptr) + mPosInSet(0), mSetSize(0), mParent(nullptr), mItem(aItem), mRole(aRole) { MOZ_COUNT_CTOR(AccGroupInfo); - Accessible* parent = aItem->Parent(); + Update(); +} + +void +AccGroupInfo::Update() +{ + Accessible* parent = mItem->Parent(); if (!parent) return; - int32_t indexInParent = aItem->IndexInParent(); + int32_t indexInParent = mItem->IndexInParent(); uint32_t siblingCount = parent->ChildCount(); if (indexInParent == -1 || indexInParent >= static_cast(siblingCount)) { @@ -26,7 +32,7 @@ AccGroupInfo::AccGroupInfo(Accessible* aItem, role aRole) : return; } - int32_t level = nsAccUtils::GetARIAOrDefaultLevel(aItem); + int32_t level = nsAccUtils::GetARIAOrDefaultLevel(mItem); // Compute position in set. mPosInSet = 1; @@ -39,7 +45,7 @@ AccGroupInfo::AccGroupInfo(Accessible* aItem, role aRole) : break; // If sibling is not visible and hasn't the same base role. - if (BaseRole(siblingRole) != aRole || sibling->State() & states::INVISIBLE) + if (BaseRole(siblingRole) != mRole || sibling->State() & states::INVISIBLE) continue; // Check if it's hierarchical flatten structure, i.e. if the sibling @@ -81,7 +87,7 @@ AccGroupInfo::AccGroupInfo(Accessible* aItem, role aRole) : break; // If sibling is visible and has the same base role - if (BaseRole(siblingRole) != aRole || sibling->State() & states::INVISIBLE) + if (BaseRole(siblingRole) != mRole || sibling->State() & states::INVISIBLE) continue; // and check if it's hierarchical flatten structure. @@ -108,7 +114,7 @@ AccGroupInfo::AccGroupInfo(Accessible* aItem, role aRole) : return; roles::Role parentRole = parent->Role(); - if (ShouldReportRelations(aRole, parentRole)) + if (ShouldReportRelations(mRole, parentRole)) mParent = parent; // ARIA tree and list can be arranged by using ARIA groups to organize levels. @@ -119,9 +125,9 @@ AccGroupInfo::AccGroupInfo(Accessible* aItem, role aRole) : // parent. In other words the parent of the tree item will be a group and // the previous tree item of the group is a conceptual parent of the tree // item. - if (aRole == roles::OUTLINEITEM) { + if (mRole == roles::OUTLINEITEM) { Accessible* parentPrevSibling = parent->PrevSibling(); - if (parentPrevSibling && parentPrevSibling->Role() == aRole) { + if (parentPrevSibling && parentPrevSibling->Role() == mRole) { mParent = parentPrevSibling; return; } @@ -130,9 +136,9 @@ AccGroupInfo::AccGroupInfo(Accessible* aItem, role aRole) : // Way #2 for ARIA list and tree: group is a child of an item. In other words // the parent of the item will be a group and containing item of the group is // a conceptual parent of the item. - if (aRole == roles::LISTITEM || aRole == roles::OUTLINEITEM) { + if (mRole == roles::LISTITEM || mRole == roles::OUTLINEITEM) { Accessible* grandParent = parent->Parent(); - if (grandParent && grandParent->Role() == aRole) + if (grandParent && grandParent->Role() == mRole) mParent = grandParent; } } diff --git a/accessible/src/base/AccGroupInfo.h b/accessible/src/base/AccGroupInfo.h index dac2463bb62..a1e30a2df8a 100644 --- a/accessible/src/base/AccGroupInfo.h +++ b/accessible/src/base/AccGroupInfo.h @@ -34,6 +34,11 @@ public: */ Accessible* ConceptualParent() const { return mParent; } + /** + * Update group information. + */ + void Update(); + /** * Create group info. */ @@ -99,6 +104,8 @@ private: uint32_t mPosInSet; uint32_t mSetSize; Accessible* mParent; + Accessible* mItem; + a11y::role mRole; }; } // namespace mozilla diff --git a/accessible/src/base/NotificationController.h b/accessible/src/base/NotificationController.h index 24ac4bfe72e..f66830afce3 100644 --- a/accessible/src/base/NotificationController.h +++ b/accessible/src/base/NotificationController.h @@ -89,8 +89,8 @@ public: NotificationController(DocAccessible* aDocument, nsIPresShell* aPresShell); virtual ~NotificationController(); - NS_IMETHOD_(nsrefcnt) AddRef(void); - NS_IMETHOD_(nsrefcnt) Release(void); + NS_IMETHOD_(MozExternalRefCountType) AddRef(void); + NS_IMETHOD_(MozExternalRefCountType) Release(void); NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(NotificationController) diff --git a/accessible/src/base/nsAccessiblePivot.cpp b/accessible/src/base/nsAccessiblePivot.cpp index c4094147fa1..39f041ba691 100644 --- a/accessible/src/base/nsAccessiblePivot.cpp +++ b/accessible/src/base/nsAccessiblePivot.cpp @@ -52,7 +52,6 @@ NS_IMPL_CYCLE_COLLECTION_3(nsAccessiblePivot, mRoot, mPosition, mObservers) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsAccessiblePivot) NS_INTERFACE_MAP_ENTRY(nsIAccessiblePivot) - NS_INTERFACE_MAP_ENTRY(nsAccessiblePivot) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAccessiblePivot) NS_INTERFACE_MAP_END diff --git a/accessible/src/generic/Accessible.cpp b/accessible/src/generic/Accessible.cpp index a525e7b9010..1e5d44fcb84 100644 --- a/accessible/src/generic/Accessible.cpp +++ b/accessible/src/generic/Accessible.cpp @@ -2522,6 +2522,7 @@ Accessible::BindToParent(Accessible* aParent, uint32_t aIndexInParent) if (mParent != aParent) { NS_ERROR("Adopting child!"); mParent->RemoveChild(this); + mParent->InvalidateChildrenGroupInfo(); } else { NS_ERROR("Binding to the same parent!"); return; @@ -2530,12 +2531,15 @@ Accessible::BindToParent(Accessible* aParent, uint32_t aIndexInParent) mParent = aParent; mIndexInParent = aIndexInParent; + + mParent->InvalidateChildrenGroupInfo(); } // Accessible protected void Accessible::UnbindFromParent() { + mParent->InvalidateChildrenGroupInfo(); mParent = nullptr; mIndexInParent = -1; mIndexOfEmbeddedChild = -1; @@ -3127,13 +3131,29 @@ Accessible::GetActionRule() AccGroupInfo* Accessible::GetGroupInfo() { - if (mGroupInfo) + if (mGroupInfo){ + if (HasDirtyGroupInfo()) { + mGroupInfo->Update(); + SetDirtyGroupInfo(false); + } + return mGroupInfo; + } mGroupInfo = AccGroupInfo::CreateGroupInfo(this); return mGroupInfo; } +void +Accessible::InvalidateChildrenGroupInfo() +{ + uint32_t length = mChildren.Length(); + for (uint32_t i = 0; i < length; i++) { + Accessible* child = mChildren[i]; + child->SetDirtyGroupInfo(true); + } +} + void Accessible::GetPositionAndSizeInternal(int32_t *aPosInSet, int32_t *aSetSize) { @@ -3215,13 +3235,13 @@ Accessible::GetLevelInternal() void Accessible::StaticAsserts() const { - static_assert(eLastChildrenFlag <= (2 << kChildrenFlagsBits) - 1, + static_assert(eLastChildrenFlag <= (1 << kChildrenFlagsBits) - 1, "Accessible::mChildrenFlags was oversized by eLastChildrenFlag!"); - static_assert(eLastStateFlag <= (2 << kStateFlagsBits) - 1, + static_assert(eLastStateFlag <= (1 << kStateFlagsBits) - 1, "Accessible::mStateFlags was oversized by eLastStateFlag!"); - static_assert(eLastAccType <= (2 << kTypeBits) - 1, + static_assert(eLastAccType <= (1 << kTypeBits) - 1, "Accessible::mType was oversized by eLastAccType!"); - static_assert(eLastAccGenericType <= (2 << kGenericTypesBits) - 1, + static_assert(eLastAccGenericType <= (1 << kGenericTypesBits) - 1, "Accessible::mGenericType was oversized by eLastAccGenericType!"); } diff --git a/accessible/src/generic/Accessible.h b/accessible/src/generic/Accessible.h index 19d7f3faf0f..caba51d5201 100644 --- a/accessible/src/generic/Accessible.h +++ b/accessible/src/generic/Accessible.h @@ -765,6 +765,11 @@ public: bool IsNodeMapEntry() const { return HasOwnContent() && !(mStateFlags & eNotNodeMapEntry); } + /** + * Return true if the accessible's group info needs to be updated. + */ + inline bool HasDirtyGroupInfo() const { return mStateFlags & eGroupInfoDirty; } + /** * Return true if the accessible has associated DOM content. */ @@ -856,9 +861,10 @@ protected: eSharedNode = 1 << 2, // accessible shares DOM node from another accessible eNotNodeMapEntry = 1 << 3, // accessible shouldn't be in document node map eHasNumericValue = 1 << 4, // accessible has a numeric value - eIgnoreDOMUIEvent = 1 << 5, // don't process DOM UI events for a11y events + eGroupInfoDirty = 1 << 5, // accessible needs to update group info + eIgnoreDOMUIEvent = 1 << 6, // don't process DOM UI events for a11y events - eLastStateFlag = eHasNumericValue + eLastStateFlag = eGroupInfoDirty }; protected: @@ -938,6 +944,22 @@ protected: */ AccGroupInfo* GetGroupInfo(); + /** + * Set dirty state of the accessible's group info. + */ + inline void SetDirtyGroupInfo(bool aIsDirty) + { + if (aIsDirty) + mStateFlags |= eGroupInfoDirty; + else + mStateFlags &= ~eGroupInfoDirty; + } + + /** + * Flag all children group info as needing to be updated. + */ + void InvalidateChildrenGroupInfo(); + // Data Members nsCOMPtr mContent; DocAccessible* mDoc; @@ -947,7 +969,7 @@ protected: int32_t mIndexInParent; static const uint8_t kChildrenFlagsBits = 2; - static const uint8_t kStateFlagsBits = 5; + static const uint8_t kStateFlagsBits = 6; static const uint8_t kTypeBits = 6; static const uint8_t kGenericTypesBits = 12; diff --git a/accessible/tests/mochitest/attributes/test_obj_group.html b/accessible/tests/mochitest/attributes/test_obj_group.html index e1591142745..3b4be098a4d 100644 --- a/accessible/tests/mochitest/attributes/test_obj_group.html +++ b/accessible/tests/mochitest/attributes/test_obj_group.html @@ -12,6 +12,8 @@ src="../common.js"> + @@ -27,7 +26,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=857555
 
diff --git a/dom/tests/mochitest/general/test_interfaces.html b/dom/tests/mochitest/general/test_interfaces.html index be1d8d05b9c..aa3f999ee43 100644 --- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -347,6 +347,8 @@ var interfaceNamesInGlobalScope = "EventSource", // IMPORTANT: Do not change this list without review from a DOM peer! "EventTarget", +// IMPORTANT: Do not change this list without review from a DOM peer! + {name: "External", b2g: false}, // IMPORTANT: Do not change this list without review from a DOM peer! "File", // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/dom/webidl/External.webidl b/dom/webidl/External.webidl new file mode 100644 index 00000000000..d7b0863123c --- /dev/null +++ b/dom/webidl/External.webidl @@ -0,0 +1,18 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +[JSImplementation="@mozilla.org/sidebar;1"] +interface External +{ + void AddSearchProvider(DOMString aDescriptionURL); + unsigned long IsSearchProviderInstalled(DOMString aSearchURL); +}; + +// Mozilla extension +partial interface External { + void addSearchEngine(DOMString engineURL, DOMString iconURL, + DOMString suggestedTitle, DOMString suggestedCategory); +}; diff --git a/dom/webidl/Window.webidl b/dom/webidl/Window.webidl index fd2c1363ce3..a93225c44c4 100644 --- a/dom/webidl/Window.webidl +++ b/dom/webidl/Window.webidl @@ -65,7 +65,9 @@ typedef any Transferable; // the user agent [Throws] readonly attribute Navigator navigator; - //(Not implemented)readonly attribute External external; +#ifdef HAVE_SIDEBAR + [Replaceable, Throws] readonly attribute External external; +#endif [Throws] readonly attribute ApplicationCache applicationCache; // user prompts @@ -348,6 +350,13 @@ partial interface Window { readonly attribute Console console; }; +#ifdef HAVE_SIDEBAR +// Mozilla extension +partial interface Window { + [Replaceable, Throws] + readonly attribute (External or WindowProxy) sidebar; +}; +#endif [ChromeOnly] interface ChromeWindow { [Func="nsGlobalWindow::IsChromeWindow"] diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index 25090b20059..f503b7cc2f6 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -621,3 +621,8 @@ if CONFIG['MOZ_BUILD_APP'] in ['browser', 'xulrunner']: WEBIDL_FILES += [ 'BrowserFeedWriter.webidl', ] + +if CONFIG['MOZ_BUILD_APP'] in ['browser', 'mobile/android', 'xulrunner']: + WEBIDL_FILES += [ + 'External.webidl', + ] diff --git a/dom/workers/XMLHttpRequest.cpp b/dom/workers/XMLHttpRequest.cpp index 1fd1133e0f6..ac527babc68 100644 --- a/dom/workers/XMLHttpRequest.cpp +++ b/dom/workers/XMLHttpRequest.cpp @@ -427,13 +427,12 @@ public: class StateDataAutoRooter : private JS::CustomAutoRooter { XMLHttpRequest::StateData* mStateData; - js::SkipRoot mSkip; MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER public: explicit StateDataAutoRooter(JSContext* aCx, XMLHttpRequest::StateData* aData MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : CustomAutoRooter(aCx), mStateData(aData), mSkip(aCx, mStateData) + : CustomAutoRooter(aCx), mStateData(aData) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } diff --git a/dom/xbl/XBLChildrenElement.cpp b/dom/xbl/XBLChildrenElement.cpp index cd5a52b3bd8..ee3b81bb610 100644 --- a/dom/xbl/XBLChildrenElement.cpp +++ b/dom/xbl/XBLChildrenElement.cpp @@ -82,9 +82,8 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(nsAnonymousContentList) NS_INTERFACE_TABLE_HEAD(nsAnonymousContentList) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY - NS_INTERFACE_TABLE_INHERITED3(nsAnonymousContentList, nsINodeList, - nsIDOMNodeList, - nsAnonymousContentList) + NS_INTERFACE_TABLE_INHERITED2(nsAnonymousContentList, nsINodeList, + nsIDOMNodeList) NS_INTERFACE_TABLE_TO_MAP_SEGUE NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsAnonymousContentList) NS_INTERFACE_MAP_ENTRY(nsISupports) diff --git a/dom/xbl/moz.build b/dom/xbl/moz.build index c808bce44ff..064c6c6db0d 100644 --- a/dom/xbl/moz.build +++ b/dom/xbl/moz.build @@ -50,7 +50,6 @@ LOCAL_INCLUDES += [ '/dom/base', '/dom/events', '/layout/style', - '/xpcom/ds', ] FINAL_LIBRARY = 'gklayout' diff --git a/dom/xslt/xslt/txStylesheetCompiler.h b/dom/xslt/xslt/txStylesheetCompiler.h index 2e4208a9791..baef8c3c66f 100644 --- a/dom/xslt/xslt/txStylesheetCompiler.h +++ b/dom/xslt/xslt/txStylesheetCompiler.h @@ -45,8 +45,8 @@ public: class txACompileObserver { public: - NS_IMETHOD_(nsrefcnt) AddRef() = 0; - NS_IMETHOD_(nsrefcnt) Release() = 0; + NS_IMETHOD_(MozExternalRefCountType) AddRef() = 0; + NS_IMETHOD_(MozExternalRefCountType) Release() = 0; virtual nsresult loadURI(const nsAString& aUri, const nsAString& aReferrerUri, diff --git a/editor/txmgr/src/nsTransactionItem.h b/editor/txmgr/src/nsTransactionItem.h index 38d2cf4e41d..518f3d78d81 100644 --- a/editor/txmgr/src/nsTransactionItem.h +++ b/editor/txmgr/src/nsTransactionItem.h @@ -27,8 +27,8 @@ public: nsTransactionItem(nsITransaction *aTransaction); virtual ~nsTransactionItem(); - NS_METHOD_(nsrefcnt) AddRef(); - NS_METHOD_(nsrefcnt) Release(); + NS_METHOD_(MozExternalRefCountType) AddRef(); + NS_METHOD_(MozExternalRefCountType) Release(); NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsTransactionItem) diff --git a/embedding/components/printingui/src/win/nsPrintProgress.cpp b/embedding/components/printingui/src/win/nsPrintProgress.cpp index 073de06bd69..d711bddb132 100644 --- a/embedding/components/printingui/src/win/nsPrintProgress.cpp +++ b/embedding/components/printingui/src/win/nsPrintProgress.cpp @@ -16,7 +16,7 @@ NS_IMPL_ADDREF(nsPrintProgress) NS_IMPL_RELEASE(nsPrintProgress) #else -NS_IMETHODIMP_(nsrefcnt) nsPrintProgress::AddRef(void) +NS_IMETHODIMP_(MozExternalRefCountType) nsPrintProgress::AddRef(void) { NS_PRECONDITION(int32_t(mRefCnt) >= 0, "illegal refcnt"); nsrefcnt count; @@ -25,7 +25,7 @@ NS_IMETHODIMP_(nsrefcnt) nsPrintProgress::AddRef(void) return count; } -NS_IMETHODIMP_(nsrefcnt) nsPrintProgress::Release(void) +NS_IMETHODIMP_(MozExternalRefCountType) nsPrintProgress::Release(void) { nsrefcnt count; NS_PRECONDITION(0 != mRefCnt, "dup release"); diff --git a/extensions/cookie/nsPopupWindowManager.cpp b/extensions/cookie/nsPopupWindowManager.cpp index 010df534e01..e6b05470619 100644 --- a/extensions/cookie/nsPopupWindowManager.cpp +++ b/extensions/cookie/nsPopupWindowManager.cpp @@ -34,7 +34,7 @@ nsPopupWindowManager::~nsPopupWindowManager() NS_IMPL_ISUPPORTS3(nsPopupWindowManager, nsIPopupWindowManager, nsIObserver, - nsSupportsWeakReference) + nsISupportsWeakReference) nsresult nsPopupWindowManager::Init() diff --git a/extensions/permissions/nsContentBlocker.cpp b/extensions/permissions/nsContentBlocker.cpp index 05e1f54ad52..1ecf4c4ee3b 100644 --- a/extensions/permissions/nsContentBlocker.cpp +++ b/extensions/permissions/nsContentBlocker.cpp @@ -47,7 +47,7 @@ uint8_t nsContentBlocker::mBehaviorPref[NUMBER_OF_TYPES]; NS_IMPL_ISUPPORTS3(nsContentBlocker, nsIContentPolicy, nsIObserver, - nsSupportsWeakReference) + nsISupportsWeakReference) nsContentBlocker::nsContentBlocker() { diff --git a/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/upstream-hunspell.diff b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/upstream-hunspell.diff index 9afb3beb517..4588e933f12 100644 --- a/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/upstream-hunspell.diff +++ b/extensions/spellcheck/locales/en-US/hunspell/dictionary-sources/upstream-hunspell.diff @@ -9227,415 +9227,417 @@ --- > dialog/SMGD > dialogue/SMRGD -20481a26296 +20220a26035 +> diatomaceous +20481a26297 > disclose/DSG -20830c26645 +20830c26646 < dogie/M --- > dogie/SM -20895a26711 +20895a26712 > donator/MS -21820a27637 +21820a27638 > elicitor/MS -22071a27889 +22071a27890 > encyclopaedia -22196a28015 +22196a28016 > enqueue/DSG -22556a28376 +22556a28377 > estoppel -22638c28458 +22638c28459 < euthanize --- > euthanize/DSG -22719a28540 +22719a28541 > exabyte/MS -22947a28769 +22947a28770 > experimentalism -23207,23208d29028 +23207,23208d29029 < faecal < faeces/M -23215c29035 +23215c29036 < faggoting's --- > faggot/SMG -23701a29522 +23701a29523 > filesystem/MS -24155c29976 +24155c29977 < fluidized --- > fluidize/DSG -24216a30038 +24216a30039 > foci -24736d30557 +24736d30558 < frier/M -24855,24856c30676,30677 +24855,24856c30677,30678 < fucker/M! < fuckhead/S! --- > fucker/SM! > fuckhead/SM! -24953d30773 +24953d30774 < furore/MS -25125c30945 +25125c30946 < gaolbird/S --- > gaolbirds -25180d30999 +25180d31000 < gasolene/M -25190a31010 +25190a31011 > gastroenterologist/M -25262c31082 +25262c31083 < geezer/M --- > geezer/MS -25327c31147 +25327c31148 < genomic --- > genomic/S -25462a31283 +25462a31284 > gigabit/MS -25464a31286,31288 +25464a31287,31289 > gigajoule/MS > gigapixel/MS > gigawatt/MS -25560d31383 +25560d31384 < glamourize/DSG -25674c31497 +25674c31498 < glycerine's --- > glycerine/M -25905c31728 +25905c31729 < gram/MS --- > gram/KMS -25909d31731 +25909d31732 < gramme/SM -26063c31885,31886 +26063c31886,31887 < greybeard --- > grey/MDRTGSP > greybeard/SM -26066c31889 +26066c31890 < greyness --- > greyness/M -26246,26247d32068 +26246,26247d32069 < guerilla's < guerillas -26432,26436d32252 +26432,26436d32253 < haemoglobin's < haemophilia/M < haemorrhage/DSMG < haemorrhoid/S < haemorrhoids/M -27167c32983 +27167c32984 < hexane --- > hexane/SM -27273a33090 +27273a33091 > hippopotami -27875d33691 +27875d33692 < hyaena/SM -28017c33833 +28017c33834 < iPod/M --- > iPod/MS -28105a33922 +28105a33923 > idolator/SM -28513c34330 +28513c34331 < inbound --- > inbound/s -28650a34468 +28650a34469 > indices -28812d34629 +28812d34630 < inflexion/SM -29216a35034 +29216a35035 > intern/GDL -29266a35085 +29266a35086 > interruptible/U -29272a35092,35095 +29272a35093,35096 > intersex > intersexual/MS > intersexualism > intersexuality -29724c35547 +29724c35548 < jewellery's --- > jewellery/M -29870a35694 +29870a35695 > judgement/MS -30066c35890 +30066c35891 < kiddie/M --- > kiddie/SM -30262,30263c36086 +30262,30263c36087 < kraut's < kraut/S! --- > kraut/MS! -30665a36489 +30665a36490 > lector/MS -31031c36855 +31031c36856 < linguini's --- > linguini/M -31034c36858 +31034c36859 < linguistically --- > linguistical/Y -31151,31152c36975 +31151,31152c36976 < liver's < liver/S --- > liver/MS -32230c38053 +32230c38054 < meanie/M --- > meanie/MS -32317,32318c38140 +32317,32318c38141 < megadeath/M < megadeaths --- > megadeath/SM -32320c38142 +32320c38143 < megajoules --- > megajoule/SM -32329c38151 +32329c38152 < megapixel/S --- > megapixel/MS -32708a38531 +32708a38532 > might've -32717a38541 +32717a38542 > migrator/SM -32760a38585 +32760a38586 > millennia -32777d38601 +32777d38602 < millionnaire/M -32934a38759 +32934a38760 > miscommunication/S -32991a38817 +32991a38818 > misjudgement/MS -33784a39611 +33784a39612 > must've -33963c39790 +33963c39791 < native/MS --- > native/MSY -34169,34171c39996,39997 +34169,34171c39997,39998 < neurone/S < neurophysiology < neuroscience --- > neurophysiology/M > neuroscience/MS -34275c40101 +34275c40102 < nightie/M --- > nightie/SM -35104a40931 +35104a40932 > octopi -35219d41045 +35219d41046 < oleomargarin/M -35226a41053 +35226a41054 > oligo -35913c41740 +35913c41741 < oversize/D --- > oversize -36056,36059d41882 +36056,36059d41883 < paederast/S < paediatrician's < paediatricians < paediatrics/M -36291a42115 +36291a42116 > paralyses -36403d42226 +36403d42227 < parrakeet/MS -36449d42271 +36449d42272 < partizan/SM -37093a42916 +37093a42917 > petabyte/MS -37102c42925 +37102c42926 < petitioner/M --- > petitioner/MS -37264a43088 +37264a43089 > phosphorylate/DSGN -37316d43139 +37316d43140 < phrenetic -37630a43454 +37630a43455 > plaintext -37796a43621 +37796a43622 > plugin/MS -37987c43812 +37987c43813 < polypeptide/S --- > polypeptide/MS -38291d44115 +38291d44116 < practise's -38451a44276 +38451a44277 > prejudgement/MS -38805a44631 +38805a44632 > profiler/SM -38835a44662 +38835a44663 > programmatically -38891a44719,44720 +38891a44720,44721 > pronate/DSGN > pronator/MS -38951c44780 +38951c44781 < proprietorship/M --- > proprietorship/MS -39039a44869 +39039a44870 > provender/M -39095a44926 +39095a44927 > pseudorandom/Y -39564a45396 +39564a45397 > quinoa -39873a45706,45707 +39873a45707,45708 > rasterization/M > rasterize/SGDR -40036a45871 +40036a45872 > recency -40140a45976 +40140a45977 > recurse/DGSV -40141a45978 +40141a45979 > recuse/DGS -40208a46046 +40208a46047 > refactor/SMDG -40244d46081 +40244d46082 < reflexion/SM -40659d46495 +40659d46496 < resizing -40829c46665 +40829c46666 < reverie/M --- > reverie/MS -41415a47252 +41415a47253 > sabre/MS -41914c47751 +41914c47752 < schnaps's --- > schnaps/M -41949c47786 +41949c47787 < schrod's --- > schrod/SM -41998a47836 +41998a47837 > scot-free -42883,42885c48721 +42883,42885c48722 < shit's < shit/S! < shite/S! --- > shit/MS! -42887,42888c48723,48724 +42887,42888c48724,48725 < shithead/S! < shitload/! --- > shithead/MS! > shitload/MS! -42891c48727 +42891c48728 < shitty/RT! --- > shitty/TR! -42976a48813 +42976a48814 > should've -43008c48845 +43008c48846 < showtime --- > showtime/MS -43328c49165 +43328c49166 < size/MGBDRS --- > size/AMGBDRS -43724,43726c49561 +43724,43726c49562 < smoulder's < smouldered < smoulders --- > smoulder/GSMD -43766a49602,49603 +43766a49603,49604 > snarkily > snarky/TR -44062c49899 +44062c49900 < sonofabitch --- > sonofabitch/! -44346a50184 +44346a50185 > spelled -44348a50187 +44348a50188 > spelt -44371a50211 +44371a50212 > spick/S! -44383c50223 +44383c50224 < spik/S --- > spik/S! -46106a51947 +46106a51948 > syllabi -46160c52001 +46160c52002 < synch/GMD --- > synch/GMDS -46167d52007 +46167d52008 < synchs -46203,46204c52043,52044 +46203,46204c52044,52045 < sysadmin/S < sysop/S --- > sysadmin/MS > sysop/MS -46752a52593 +46752a52594 > terabit/MS -46753a52595,52596 +46753a52596,52597 > terahertz/M > terapixel/MS -46817a52661 +46817a52662 > testcase/MS -46831a52676 +46831a52677 > testsuite/MS -46925a52771 +46925a52772 > theremin/MS -47455c53301 +47455c53302 < toolbar --- > toolbar/MS -47755a53602 +47755a53603 > transfect/DSMG -47774a53622,53623 +47774a53623,53624 > transgenderism > transgene/MS -47951c53800 +47951c53801 < triage/M --- > triage/MG -48869a54719 +48869a54720 > unlikeable -49211c55061 +49211c55062 < vagina/M --- > vagina/MS -49368,49369c55218 +49368,49369c55219 < velour's < velours's --- > velour/MS -49478a55328 +49478a55329 > vertices -50148a55999 +50148a56000 > weaponize/DSG -50260,50261d56110 +50260,50261d56111 < werwolf/M < werwolves -50728c56577 +50728c56578 < women --- > women/M -50794c56643 +50794c56644 < wop/S! --- > wop/MS! diff --git a/extensions/spellcheck/locales/en-US/hunspell/en-US.dic b/extensions/spellcheck/locales/en-US/hunspell/en-US.dic index 72938d8ac62..b9d586ac8d1 100644 --- a/extensions/spellcheck/locales/en-US/hunspell/en-US.dic +++ b/extensions/spellcheck/locales/en-US/hunspell/en-US.dic @@ -1,4 +1,4 @@ -57465 +57466 0/nm 0th/pt 1/n1 @@ -26305,6 +26305,7 @@ diastole/M diastolic diathermy/M diatom/SM +diatomaceous diatomic diatonic diatribe/SM diff --git a/gfx/layers/Compositor.h b/gfx/layers/Compositor.h index 99592ab3d05..5cd8d9302c1 100644 --- a/gfx/layers/Compositor.h +++ b/gfx/layers/Compositor.h @@ -325,9 +325,9 @@ public: { /* Should turn into pure virtual once implemented in D3D */ } /* - * Clear aRect on FrameBuffer. + * Clear aRect on current render target. */ - virtual void clearFBRect(const gfx::Rect* aRect) { } + virtual void ClearRect(const gfx::Rect& aRect) { } /** * Start a new frame. diff --git a/gfx/layers/FrameMetrics.h b/gfx/layers/FrameMetrics.h index e16511d82cf..ceb0f79c383 100644 --- a/gfx/layers/FrameMetrics.h +++ b/gfx/layers/FrameMetrics.h @@ -162,17 +162,17 @@ public: CSSRect GetExpandedScrollableRect() const { CSSRect scrollableRect = mScrollableRect; - CSSRect compBounds = CSSRect(CalculateCompositedRectInCssPixels()); - if (scrollableRect.width < compBounds.width) { + CSSSize compSize = CalculateCompositedSizeInCssPixels(); + if (scrollableRect.width < compSize.width) { scrollableRect.x = std::max(0.f, - scrollableRect.x - (compBounds.width - scrollableRect.width)); - scrollableRect.width = compBounds.width; + scrollableRect.x - (compSize.width - scrollableRect.width)); + scrollableRect.width = compSize.width; } - if (scrollableRect.height < compBounds.height) { + if (scrollableRect.height < compSize.height) { scrollableRect.y = std::max(0.f, - scrollableRect.y - (compBounds.height - scrollableRect.height)); - scrollableRect.height = compBounds.height; + scrollableRect.y - (compSize.height - scrollableRect.height)); + scrollableRect.height = compSize.height; } return scrollableRect; @@ -195,9 +195,14 @@ public: return mZoom * mTransformScale; } - CSSIntRect CalculateCompositedRectInCssPixels() const + CSSSize CalculateCompositedSizeInCssPixels() const { - return gfx::RoundedIn(mCompositionBounds / GetZoomToParent()); + return mCompositionBounds.Size() / GetZoomToParent(); + } + + CSSRect CalculateCompositedRectInCssPixels() const + { + return mCompositionBounds / GetZoomToParent(); } void ScrollBy(const CSSPoint& aPoint) @@ -210,6 +215,12 @@ public: mZoom.scale *= aFactor; } + void CopyScrollInfoFrom(const FrameMetrics& aOther) + { + mScrollOffset = aOther.mScrollOffset; + mScrollGeneration = aOther.mScrollGeneration; + } + // --------------------------------------------------------------------------- // The following metrics are all in widget space/device pixels. // diff --git a/gfx/layers/client/CanvasClient.cpp b/gfx/layers/client/CanvasClient.cpp index 508120e511a..cc19ea6d23c 100644 --- a/gfx/layers/client/CanvasClient.cpp +++ b/gfx/layers/client/CanvasClient.cpp @@ -110,6 +110,7 @@ CanvasClientSurfaceStream::CanvasClientSurfaceStream(CompositableForwarder* aLay void CanvasClientSurfaceStream::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) { + aLayer->mGLContext->MakeCurrent(); GLScreenBuffer* screen = aLayer->mGLContext->Screen(); SurfaceStream* stream = nullptr; diff --git a/gfx/layers/client/ClientLayerManager.cpp b/gfx/layers/client/ClientLayerManager.cpp index fea1e667f2c..3359d46f912 100644 --- a/gfx/layers/client/ClientLayerManager.cpp +++ b/gfx/layers/client/ClientLayerManager.cpp @@ -352,7 +352,7 @@ ClientLayerManager::ForwardTransaction(bool aScheduleComposite) // forward this transaction's changeset to our LayerManagerComposite bool sent; AutoInfallibleTArray replies; - if (HasShadowManager() && mForwarder->EndTransaction(&replies, aScheduleComposite, &sent)) { + if (HasShadowManager() && mForwarder->EndTransaction(&replies, mRegionToClear, aScheduleComposite, &sent)) { for (nsTArray::size_type i = 0; i < replies.Length(); ++i) { const EditReply& reply = replies[i]; diff --git a/gfx/layers/client/TiledContentClient.cpp b/gfx/layers/client/TiledContentClient.cpp index 2e8d8b12e42..a08841b4b0d 100644 --- a/gfx/layers/client/TiledContentClient.cpp +++ b/gfx/layers/client/TiledContentClient.cpp @@ -241,7 +241,7 @@ bool SharedFrameMetricsHelper::AboutToCheckerboard(const FrameMetrics& aContentMetrics, const FrameMetrics& aCompositorMetrics) { - return !aContentMetrics.mDisplayPort.Contains(CSSRect(aCompositorMetrics.CalculateCompositedRectInCssPixels()) - aCompositorMetrics.GetScrollOffset()); + return !aContentMetrics.mDisplayPort.Contains(aCompositorMetrics.CalculateCompositedRectInCssPixels() - aCompositorMetrics.GetScrollOffset()); } ClientTiledLayerBuffer::ClientTiledLayerBuffer(ClientTiledThebesLayer* aThebesLayer, diff --git a/gfx/layers/composite/AsyncCompositionManager.cpp b/gfx/layers/composite/AsyncCompositionManager.cpp index cabcbc605d4..cf35f9cb571 100644 --- a/gfx/layers/composite/AsyncCompositionManager.cpp +++ b/gfx/layers/composite/AsyncCompositionManager.cpp @@ -619,12 +619,12 @@ AsyncCompositionManager::ApplyAsyncTransformToScrollbar(ContainerLayer* aLayer) Matrix4x4 scrollbarTransform; if (aLayer->GetScrollbarDirection() == Layer::VERTICAL) { - float scale = metrics.CalculateCompositedRectInCssPixels().height / metrics.mScrollableRect.height; + float scale = metrics.CalculateCompositedSizeInCssPixels().height / metrics.mScrollableRect.height; scrollbarTransform = scrollbarTransform * Matrix4x4().Scale(1.f, 1.f / transientTransform.GetYScale(), 1.f); scrollbarTransform = scrollbarTransform * Matrix4x4().Translate(0, -transientTransform._42 * scale, 0); } if (aLayer->GetScrollbarDirection() == Layer::HORIZONTAL) { - float scale = metrics.CalculateCompositedRectInCssPixels().width / metrics.mScrollableRect.width; + float scale = metrics.CalculateCompositedSizeInCssPixels().width / metrics.mScrollableRect.width; scrollbarTransform = scrollbarTransform * Matrix4x4().Scale(1.f / transientTransform.GetXScale(), 1.f, 1.f); scrollbarTransform = scrollbarTransform * Matrix4x4().Translate(-transientTransform._41 * scale, 0, 0); } diff --git a/gfx/layers/composite/ContainerLayerComposite.cpp b/gfx/layers/composite/ContainerLayerComposite.cpp index bd42c6ac4f5..741542faa9a 100644 --- a/gfx/layers/composite/ContainerLayerComposite.cpp +++ b/gfx/layers/composite/ContainerLayerComposite.cpp @@ -373,7 +373,7 @@ ContainerRender(ContainerT* aContainer, if (!clearRect.IsEmpty()) { // Clear layer's visible rect on FrameBuffer with transparent pixels gfx::Rect fbRect(clearRect.x, clearRect.y, clearRect.width, clearRect.height); - compositor->clearFBRect(&fbRect); + compositor->ClearRect(fbRect); layerToRender->SetClearRect(nsIntRect(0, 0, 0, 0)); } } else { diff --git a/gfx/layers/composite/LayerManagerComposite.cpp b/gfx/layers/composite/LayerManagerComposite.cpp index 4483844c238..062a5569468 100644 --- a/gfx/layers/composite/LayerManagerComposite.cpp +++ b/gfx/layers/composite/LayerManagerComposite.cpp @@ -497,6 +497,14 @@ LayerManagerComposite::Render() // Render our layers. RootLayer()->RenderLayer(clipRect); + if (!mRegionToClear.IsEmpty()) { + nsIntRegionRectIterator iter(mRegionToClear); + const nsIntRect *r; + while ((r = iter.Next())) { + mCompositor->ClearRect(Rect(r->x, r->y, r->width, r->height)); + } + } + // Allow widget to render a custom foreground. mCompositor->GetWidget()->DrawWindowOverlay(this, nsIntRect(actualBounds.x, actualBounds.y, diff --git a/gfx/layers/d3d11/CompositorD3D11.cpp b/gfx/layers/d3d11/CompositorD3D11.cpp index d61277748ec..8dc5ea357d9 100644 --- a/gfx/layers/d3d11/CompositorD3D11.cpp +++ b/gfx/layers/d3d11/CompositorD3D11.cpp @@ -58,6 +58,7 @@ struct DeviceAttachmentsD3D11 RefPtr mPremulBlendState; RefPtr mNonPremulBlendState; RefPtr mComponentBlendState; + RefPtr mDisabledBlendState; }; CompositorD3D11::CompositorD3D11(nsIWidget* aWidget) @@ -243,6 +244,18 @@ CompositorD3D11::Initialize() return false; } } + + D3D11_RENDER_TARGET_BLEND_DESC rtBlendDisabled = { + FALSE, + D3D11_BLEND_SRC_ALPHA, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD, + D3D11_BLEND_ONE, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD, + D3D11_COLOR_WRITE_ENABLE_ALL + }; + blendDesc.RenderTarget[0] = rtBlendDisabled; + hr = mDevice->CreateBlendState(&blendDesc, byRef(mAttachments->mDisabledBlendState)); + if (FAILED(hr)) { + return false; + } } nsRefPtr dxgiDevice; @@ -488,6 +501,41 @@ CompositorD3D11::SetPSForEffect(Effect* aEffect, MaskType aMaskType, gfx::Surfac } } +void +CompositorD3D11::ClearRect(const gfx::Rect& aRect) +{ + mContext->OMSetBlendState(mAttachments->mDisabledBlendState, sBlendFactor, 0xFFFFFFFF); + + Matrix4x4 identity; + memcpy(&mVSConstants.layerTransform, &identity._11, 64); + + mVSConstants.layerQuad = aRect; + mVSConstants.renderTargetOffset[0] = 0; + mVSConstants.renderTargetOffset[1] = 0; + mPSConstants.layerOpacity[0] = 1.0f; + + D3D11_RECT scissor; + scissor.left = aRect.x; + scissor.right = aRect.XMost(); + scissor.top = aRect.y; + scissor.bottom = aRect.YMost(); + mContext->RSSetScissorRects(1, &scissor); + mContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + mContext->VSSetShader(mAttachments->mVSQuadShader[MaskNone], nullptr, 0); + + mContext->PSSetShader(mAttachments->mSolidColorShader[MaskNone], nullptr, 0); + mPSConstants.layerColor[0] = 0; + mPSConstants.layerColor[1] = 0; + mPSConstants.layerColor[2] = 0; + mPSConstants.layerColor[3] = 0; + + UpdateConstantBuffers(); + + mContext->Draw(4, 0); + + mContext->OMSetBlendState(mAttachments->mPremulBlendState, sBlendFactor, 0xFFFFFFFF); +} + void CompositorD3D11::DrawQuad(const gfx::Rect& aRect, const gfx::Rect& aClipRect, diff --git a/gfx/layers/d3d11/CompositorD3D11.h b/gfx/layers/d3d11/CompositorD3D11.h index 3301a185c7c..e110f04f123 100644 --- a/gfx/layers/d3d11/CompositorD3D11.h +++ b/gfx/layers/d3d11/CompositorD3D11.h @@ -90,6 +90,8 @@ public: // If the offset is 0, 0 that's okay. } + virtual void ClearRect(const gfx::Rect& aRect) MOZ_OVERRIDE; + virtual void DrawQuad(const gfx::Rect &aRect, const gfx::Rect &aClipRect, const EffectChain &aEffectChain, diff --git a/gfx/layers/d3d9/CompositorD3D9.cpp b/gfx/layers/d3d9/CompositorD3D9.cpp index 28b964f7b66..305c6f515d0 100644 --- a/gfx/layers/d3d9/CompositorD3D9.cpp +++ b/gfx/layers/d3d9/CompositorD3D9.cpp @@ -210,6 +210,19 @@ ShaderModeForEffectType(EffectTypes aEffectType, gfx::SurfaceFormat aFormat) MOZ_CRASH("Bad effect type"); } +void +CompositorD3D9::ClearRect(const gfx::Rect& aRect) +{ + D3DRECT rect; + rect.x1 = aRect.X(); + rect.y1 = aRect.Y(); + rect.x2 = aRect.XMost(); + rect.y2 = aRect.YMost(); + + device()->Clear(1, &rect, D3DCLEAR_TARGET, + 0x00000000, 0, 0); +} + void CompositorD3D9::DrawQuad(const gfx::Rect &aRect, const gfx::Rect &aClipRect, diff --git a/gfx/layers/d3d9/CompositorD3D9.h b/gfx/layers/d3d9/CompositorD3D9.h index 1836814769b..c8b06bad052 100644 --- a/gfx/layers/d3d9/CompositorD3D9.h +++ b/gfx/layers/d3d9/CompositorD3D9.h @@ -55,6 +55,8 @@ public: virtual void SetDestinationSurfaceSize(const gfx::IntSize& aSize) MOZ_OVERRIDE {} + virtual void ClearRect(const gfx::Rect& aRect) MOZ_OVERRIDE; + virtual void DrawQuad(const gfx::Rect &aRect, const gfx::Rect &aClipRect, const EffectChain &aEffectChain, diff --git a/gfx/layers/ipc/AsyncPanZoomController.cpp b/gfx/layers/ipc/AsyncPanZoomController.cpp index 8620e3b9f3e..26eeab9b20c 100644 --- a/gfx/layers/ipc/AsyncPanZoomController.cpp +++ b/gfx/layers/ipc/AsyncPanZoomController.cpp @@ -67,14 +67,14 @@ #define APZC_LOG_FM(fm, prefix, ...) \ APZC_LOG(prefix ":" \ " i=(%ld %lld) cb=(%d %d %d %d) rcs=(%.3f %.3f) dp=(%.3f %.3f %.3f %.3f) dpm=(%.3f %.3f %.3f %.3f) um=%d " \ - "v=(%.3f %.3f %.3f %.3f) s=(%.3f %.3f) sr=(%.3f %.3f %.3f %.3f) z=(%.3f %.3f %.3f %.3f) u=(%d %llu)\n", \ + "v=(%.3f %.3f %.3f %.3f) s=(%.3f %.3f) sr=(%.3f %.3f %.3f %.3f) z=(%.3f %.3f %.3f %.3f) u=(%d %lu)\n", \ __VA_ARGS__, \ fm.mPresShellId, fm.GetScrollId(), \ fm.mCompositionBounds.x, fm.mCompositionBounds.y, fm.mCompositionBounds.width, fm.mCompositionBounds.height, \ fm.GetRootCompositionSize().width, fm.GetRootCompositionSize().height, \ fm.mDisplayPort.x, fm.mDisplayPort.y, fm.mDisplayPort.width, fm.mDisplayPort.height, \ - fm.mDisplayPortMargins.top, fm.mDisplayPortMargins.right, fm.mDisplayPortMargins.bottom, fm.mDisplayPortMargins.left, \ - fm.mUseDisplayPortMargins ? 1 : 0, \ + fm.GetDisplayPortMargins().top, fm.GetDisplayPortMargins().right, fm.GetDisplayPortMargins().bottom, fm.GetDisplayPortMargins().left, \ + fm.GetUseDisplayPortMargins() ? 1 : 0, \ fm.mViewport.x, fm.mViewport.y, fm.mViewport.width, fm.mViewport.height, \ fm.GetScrollOffset().x, fm.GetScrollOffset().y, \ fm.mScrollableRect.x, fm.mScrollableRect.y, fm.mScrollableRect.width, fm.mScrollableRect.height, \ @@ -1427,7 +1427,7 @@ const LayerMargin AsyncPanZoomController::CalculatePendingDisplayPort( const ScreenPoint& aVelocity, double aEstimatedPaintDuration) { - CSSRect compositionBounds(aFrameMetrics.CalculateCompositedRectInCssPixels()); + CSSSize compositionBounds = aFrameMetrics.CalculateCompositedSizeInCssPixels(); CSSSize compositionSize = aFrameMetrics.GetRootCompositionSize(); compositionSize = CSSSize(std::min(compositionBounds.width, compositionSize.width), @@ -1679,10 +1679,10 @@ ViewTransform AsyncPanZoomController::GetCurrentAsyncTransform() { // within rendered content. if (!gAllowCheckerboarding && !mLastContentPaintMetrics.mDisplayPort.IsEmpty()) { - CSSRect compositedRect(mLastContentPaintMetrics.CalculateCompositedRectInCssPixels()); + CSSSize compositedSize = mLastContentPaintMetrics.CalculateCompositedSizeInCssPixels(); CSSPoint maxScrollOffset = lastPaintScrollOffset + - CSSPoint(mLastContentPaintMetrics.mDisplayPort.XMost() - compositedRect.width, - mLastContentPaintMetrics.mDisplayPort.YMost() - compositedRect.height); + CSSPoint(mLastContentPaintMetrics.mDisplayPort.XMost() - compositedSize.width, + mLastContentPaintMetrics.mDisplayPort.YMost() - compositedSize.height); CSSPoint minScrollOffset = lastPaintScrollOffset + mLastContentPaintMetrics.mDisplayPort.TopLeft(); if (minScrollOffset.x < maxScrollOffset.x) { @@ -1745,6 +1745,13 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri mFrameMetrics.mViewport = aLayerMetrics.mViewport; } + // If the layers update was not triggered by our own repaint request, then + // we want to take the new scroll offset. Check the scroll generation as well + // to filter duplicate calls to NotifyLayersUpdated with the same scroll offset + // update message. + bool scrollOffsetUpdated = aLayerMetrics.GetScrollOffsetUpdated() + && (aLayerMetrics.GetScrollGeneration() != mFrameMetrics.GetScrollGeneration()); + if (aIsFirstPaint || isDefault) { // Initialize our internal state to something sane when the content // that was just painted is something we knew nothing about previously @@ -1781,14 +1788,12 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri mFrameMetrics.mCumulativeResolution = aLayerMetrics.mCumulativeResolution; mFrameMetrics.mHasScrollgrab = aLayerMetrics.mHasScrollgrab; - // If the layers update was not triggered by our own repaint request, then - // we want to take the new scroll offset. - if (aLayerMetrics.GetScrollOffsetUpdated()) { + if (scrollOffsetUpdated) { APZC_LOG("%p updating scroll offset from (%f, %f) to (%f, %f)\n", this, mFrameMetrics.GetScrollOffset().x, mFrameMetrics.GetScrollOffset().y, aLayerMetrics.GetScrollOffset().x, aLayerMetrics.GetScrollOffset().y); - mFrameMetrics.SetScrollOffset(aLayerMetrics.GetScrollOffset()); + mFrameMetrics.CopyScrollInfoFrom(aLayerMetrics); // Because of the scroll offset update, any inflight paint requests are // going to be ignored by layout, and so mLastDispatchedPaintMetrics @@ -1799,13 +1804,14 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri } } - if (aLayerMetrics.GetScrollOffsetUpdated()) { + if (scrollOffsetUpdated) { // Once layout issues a scroll offset update, it becomes impervious to // scroll offset updates from APZ until we acknowledge the update it sent. // This prevents APZ updates from clobbering scroll updates from other // more "legitimate" sources like content scripts. nsRefPtr controller = GetGeckoContentController(); if (controller) { + APZC_LOG("%p sending scroll update acknowledgement with gen %lu\n", this, aLayerMetrics.GetScrollGeneration()); controller->AcknowledgeScrollUpdate(aLayerMetrics.GetScrollId(), aLayerMetrics.GetScrollGeneration()); } @@ -1862,11 +1868,11 @@ void AsyncPanZoomController::ZoomToRect(CSSRect aRect) { if (aRect.IsEmpty() || (currentZoom == localMaxZoom && targetZoom >= localMaxZoom) || (currentZoom == localMinZoom && targetZoom <= localMinZoom)) { - CSSRect compositedRect = CSSRect(mFrameMetrics.CalculateCompositedRectInCssPixels()); + CSSSize compositedSize = mFrameMetrics.CalculateCompositedSizeInCssPixels(); float y = scrollOffset.y; float newHeight = - cssPageRect.width * (compositedRect.height / compositedRect.width); - float dh = compositedRect.height - newHeight; + cssPageRect.width * (compositedSize.height / compositedSize.width); + float dh = compositedSize.height - newHeight; aRect = CSSRect(0.0f, y + dh/2, @@ -1882,16 +1888,16 @@ void AsyncPanZoomController::ZoomToRect(CSSRect aRect) { endZoomToMetrics.SetZoom(targetZoom / mFrameMetrics.mTransformScale); // Adjust the zoomToRect to a sensible position to prevent overscrolling. - CSSRect rectAfterZoom = CSSRect(endZoomToMetrics.CalculateCompositedRectInCssPixels()); + CSSSize sizeAfterZoom = endZoomToMetrics.CalculateCompositedSizeInCssPixels(); // If either of these conditions are met, the page will be // overscrolled after zoomed - if (aRect.y + rectAfterZoom.height > cssPageRect.height) { - aRect.y = cssPageRect.height - rectAfterZoom.height; + if (aRect.y + sizeAfterZoom.height > cssPageRect.height) { + aRect.y = cssPageRect.height - sizeAfterZoom.height; aRect.y = aRect.y > 0 ? aRect.y : 0; } - if (aRect.x + rectAfterZoom.width > cssPageRect.width) { - aRect.x = cssPageRect.width - rectAfterZoom.width; + if (aRect.x + sizeAfterZoom.width > cssPageRect.width) { + aRect.x = cssPageRect.width - sizeAfterZoom.width; aRect.x = aRect.x > 0 ? aRect.x : 0; } @@ -2093,7 +2099,7 @@ void AsyncPanZoomController::SendAsyncScrollEvent() { isRoot = mFrameMetrics.mIsRoot; scrollableSize = mFrameMetrics.mScrollableRect.Size(); - contentRect = CSSRect(mFrameMetrics.CalculateCompositedRectInCssPixels()); + contentRect = mFrameMetrics.CalculateCompositedRectInCssPixels(); contentRect.MoveTo(mCurrentAsyncScrollOffset); } diff --git a/gfx/layers/ipc/Axis.cpp b/gfx/layers/ipc/Axis.cpp index 0d63f151e84..875566877e6 100644 --- a/gfx/layers/ipc/Axis.cpp +++ b/gfx/layers/ipc/Axis.cpp @@ -274,8 +274,7 @@ float Axis::GetOrigin() { float Axis::GetCompositionLength() { const FrameMetrics& metrics = mAsyncPanZoomController->GetFrameMetrics(); - CSSRect cssCompositedRect = CSSRect(metrics.CalculateCompositedRectInCssPixels()); - return GetRectLength(cssCompositedRect); + return GetRectLength(metrics.CalculateCompositedRectInCssPixels()); } float Axis::GetPageStart() { diff --git a/gfx/layers/ipc/CompositorParent.cpp b/gfx/layers/ipc/CompositorParent.cpp index 484b8a0a088..72a643d04f6 100644 --- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -740,6 +740,7 @@ CompositorParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree, // change, dimension change would be done at the stage, update the size here is free of // race condition. mLayerManager->UpdateRenderBounds(aTargetConfig.clientBounds()); + mLayerManager->SetRegionToClear(aTargetConfig.clearRegion()); mCompositionManager->Updated(aIsFirstPaint, aTargetConfig); Layer* root = aLayerTree->GetRoot(); diff --git a/gfx/layers/ipc/LayersMessages.ipdlh b/gfx/layers/ipc/LayersMessages.ipdlh index 01379541662..b779a718a05 100644 --- a/gfx/layers/ipc/LayersMessages.ipdlh +++ b/gfx/layers/ipc/LayersMessages.ipdlh @@ -49,6 +49,7 @@ struct TargetConfig { ScreenRotation rotation; nsIntRect clientBounds; ScreenOrientation orientation; + nsIntRegion clearRegion; }; // Create a shadow layer for |layer| diff --git a/gfx/layers/ipc/ShadowLayers.cpp b/gfx/layers/ipc/ShadowLayers.cpp index e0db8fe0856..cc7600a985e 100644 --- a/gfx/layers/ipc/ShadowLayers.cpp +++ b/gfx/layers/ipc/ShadowLayers.cpp @@ -465,7 +465,10 @@ ShadowLayerForwarder::RemoveTexture(TextureClient* aTexture) } bool -ShadowLayerForwarder::EndTransaction(InfallibleTArray* aReplies, bool aScheduleComposite, bool* aSent) +ShadowLayerForwarder::EndTransaction(InfallibleTArray* aReplies, + const nsIntRegion& aRegionToClear, + bool aScheduleComposite, + bool* aSent) { *aSent = false; @@ -561,7 +564,11 @@ ShadowLayerForwarder::EndTransaction(InfallibleTArray* aReplies, bool mWindowOverlayChanged = false; - TargetConfig targetConfig(mTxn->mTargetBounds, mTxn->mTargetRotation, mTxn->mClientBounds, mTxn->mTargetOrientation); + TargetConfig targetConfig(mTxn->mTargetBounds, + mTxn->mTargetRotation, + mTxn->mClientBounds, + mTxn->mTargetOrientation, + aRegionToClear); MOZ_LAYERS_LOG(("[LayersForwarder] syncing before send...")); PlatformSyncBeforeUpdate(); diff --git a/gfx/layers/ipc/ShadowLayers.h b/gfx/layers/ipc/ShadowLayers.h index be16b9f37b4..d8ad1ed17fc 100644 --- a/gfx/layers/ipc/ShadowLayers.h +++ b/gfx/layers/ipc/ShadowLayers.h @@ -329,7 +329,10 @@ public: * |aReplies| are directions from the LayerManagerComposite to the * caller of EndTransaction(). */ - bool EndTransaction(InfallibleTArray* aReplies, bool aScheduleComposite, bool* aSent); + bool EndTransaction(InfallibleTArray* aReplies, + const nsIntRegion& aRegionToClear, + bool aScheduleComposite, + bool* aSent); /** * Set an actor through which layer updates will be pushed. diff --git a/gfx/layers/opengl/CompositorOGL.cpp b/gfx/layers/opengl/CompositorOGL.cpp index 674cea6b559..b9302496435 100644 --- a/gfx/layers/opengl/CompositorOGL.cpp +++ b/gfx/layers/opengl/CompositorOGL.cpp @@ -606,17 +606,13 @@ CalculatePOTSize(const IntSize& aSize, GLContext* gl) } void -CompositorOGL::clearFBRect(const gfx::Rect* aRect) +CompositorOGL::ClearRect(const gfx::Rect& aRect) { - if (!aRect) { - return; - } - // Map aRect to OGL coordinates, origin:bottom-left - GLint y = mHeight - (aRect->y + aRect->height); + GLint y = mHeight - (aRect.y + aRect.height); ScopedGLState scopedScissorTestState(mGLContext, LOCAL_GL_SCISSOR_TEST, true); - ScopedScissorRect autoScissorRect(mGLContext, aRect->x, y, aRect->width, aRect->height); + ScopedScissorRect autoScissorRect(mGLContext, aRect.x, y, aRect.width, aRect.height); mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0); mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT); } diff --git a/gfx/layers/opengl/CompositorOGL.h b/gfx/layers/opengl/CompositorOGL.h index 8c19d9ce958..2b166a08f17 100644 --- a/gfx/layers/opengl/CompositorOGL.h +++ b/gfx/layers/opengl/CompositorOGL.h @@ -336,9 +336,9 @@ private: bool mFrameInProgress; /* - * Clear aRect on FrameBuffer. + * Clear aRect on current render target. */ - virtual void clearFBRect(const gfx::Rect* aRect); + virtual void ClearRect(const gfx::Rect& aRect) MOZ_OVERRIDE; /* Start a new frame. If aClipRectIn is null and aClipRectOut is non-null, * sets *aClipRectOut to the screen dimensions. diff --git a/gfx/qcms/iccread.c b/gfx/qcms/iccread.c index e9a933e82d5..feddffdf382 100644 --- a/gfx/qcms/iccread.c +++ b/gfx/qcms/iccread.c @@ -540,7 +540,7 @@ static struct lutmABType *read_tag_lutmABType(struct mem_source *src, struct tag uint32_t type = read_u32(src, offset); uint8_t num_in_channels, num_out_channels; struct lutmABType *lut; - int i; + uint32_t i; if (type != LUT_MAB_TYPE && type != LUT_MBA_TYPE) { return NULL; @@ -675,7 +675,7 @@ static struct lutType *read_tag_lutType(struct mem_source *src, struct tag_index uint32_t clut_size; size_t entry_size; struct lutType *lut; - int i; + uint32_t i; /* I'm not sure why the spec specifies a fixed number of entries for LUT8 tables even though * they have room for the num_entries fields */ @@ -1205,7 +1205,7 @@ static void qcms_data_from_file(FILE *file, void **mem, size_t *size) qcms_profile* qcms_profile_from_file(FILE *file) { - uint32_t length; + size_t length; qcms_profile *profile; void *data; diff --git a/gfx/thebes/gfxMacPlatformFontList.mm b/gfx/thebes/gfxMacPlatformFontList.mm index 22c8e4b9e2e..d3fd95e8b6f 100644 --- a/gfx/thebes/gfxMacPlatformFontList.mm +++ b/gfx/thebes/gfxMacPlatformFontList.mm @@ -61,6 +61,7 @@ #include "nsDirectoryServiceDefs.h" #include "nsISimpleEnumerator.h" #include "nsCharTraits.h" +#include "nsCocoaFeatures.h" #include "gfxFontConstants.h" #include "mozilla/MemoryReporting.h" @@ -1059,13 +1060,39 @@ public: virtual void Load() { nsAutoreleasePool localPool; - FontInfoData::Load(); + // bug 975460 - to disable async font loader on 10.6, bump version + if (nsCocoaFeatures::OSXVersion() >= 0x1060) { + FontInfoData::Load(); + } } // loads font data for all members of a given family virtual void LoadFontFamilyData(const nsAString& aFamilyName); }; +static CFDataRef +LoadFontTable(CTFontRef aFontRef, CTFontTableTag aTableTag) +{ + CFDataRef fontTable = nullptr; + if (!aFontRef) { + return nullptr; + } + + if (nsCocoaFeatures::OnLionOrLater()) { + fontTable = CTFontCopyTable(aFontRef, aTableTag, + kCTFontTableOptionNoOptions); + } else { + // bug 975460 - special case 10.6 to avoid CTFontCopyTable + CGFontRef cgFont = CTFontCopyGraphicsFont(aFontRef, nullptr); + if (cgFont) { + fontTable = CGFontCopyTableForTag(cgFont, aTableTag); + CFRelease(cgFont); + } + } + + return fontTable; +} + void MacFontInfo::LoadFontFamilyData(const nsAString& aFamilyName) { @@ -1122,8 +1149,7 @@ MacFontInfo::LoadFontFamilyData(const nsAString& aFamilyName) // load the cmap data FontFaceData fontData; - CFDataRef cmapTable = CTFontCopyTable(fontRef, kCTFontTableCmap, - kCTFontTableOptionNoOptions); + CFDataRef cmapTable = LoadFontTable(fontRef, kCTFontTableCmap); if (cmapTable) { bool unicodeFont = false, symbolFont = false; // ignored const uint8_t *cmapData = @@ -1149,8 +1175,7 @@ MacFontInfo::LoadFontFamilyData(const nsAString& aFamilyName) } if (mLoadOtherNames && hasOtherFamilyNames) { - CFDataRef nameTable = CTFontCopyTable(fontRef, kCTFontTableName, - kCTFontTableOptionNoOptions); + CFDataRef nameTable = LoadFontTable(fontRef, kCTFontTableName); if (nameTable) { const char *nameData = (const char*)CFDataGetBytePtr(nameTable); uint32_t nameLen = CFDataGetLength(nameTable); diff --git a/gfx/thebes/gfxPlatformMac.cpp b/gfx/thebes/gfxPlatformMac.cpp index e3c4e98a755..97b054bc6e9 100644 --- a/gfx/thebes/gfxPlatformMac.cpp +++ b/gfx/thebes/gfxPlatformMac.cpp @@ -337,13 +337,6 @@ gfxPlatformMac::GetCommonFallbackFonts(const uint32_t aCh, aFontList.AppendElement(kFontArialUnicodeMS); } - -int32_t -gfxPlatformMac::OSXVersion() -{ - return nsCocoaFeatures::OSXVersion(); -} - uint32_t gfxPlatformMac::ReadAntiAliasingThreshold() { @@ -423,7 +416,7 @@ bool gfxPlatformMac::UseAcceleratedCanvas() { // Lion or later is required - return OSXVersion() >= 0x1070 && Preferences::GetBool("gfx.canvas.azure.accelerated", false); + return nsCocoaFeatures::OnLionOrLater() && Preferences::GetBool("gfx.canvas.azure.accelerated", false); } bool diff --git a/gfx/thebes/gfxPlatformMac.h b/gfx/thebes/gfxPlatformMac.h index 605021c35a6..68c01892df2 100644 --- a/gfx/thebes/gfxPlatformMac.h +++ b/gfx/thebes/gfxPlatformMac.h @@ -69,10 +69,6 @@ public: int32_t aRunScript, nsTArray& aFontList); - // Returns the OS X version as returned from Gestalt(gestaltSystemVersion, ...) - // Ex: Mac OS X 10.4.x ==> 0x104x - int32_t OSXVersion(); - bool UseAcceleratedCanvas(); // lower threshold on font anti-aliasing diff --git a/intl/unicharutil/src/nsCaseConversionImp2.cpp b/intl/unicharutil/src/nsCaseConversionImp2.cpp index f1dac9ca1f0..f2dbd92134d 100644 --- a/intl/unicharutil/src/nsCaseConversionImp2.cpp +++ b/intl/unicharutil/src/nsCaseConversionImp2.cpp @@ -6,14 +6,14 @@ #include "nsCaseConversionImp2.h" #include "nsUnicharUtils.h" -NS_IMETHODIMP_(nsrefcnt) nsCaseConversionImp2::AddRef(void) +NS_IMETHODIMP_(MozExternalRefCountType) nsCaseConversionImp2::AddRef(void) { - return (nsrefcnt)1; + return (MozExternalRefCountType)1; } -NS_IMETHODIMP_(nsrefcnt) nsCaseConversionImp2::Release(void) +NS_IMETHODIMP_(MozExternalRefCountType) nsCaseConversionImp2::Release(void) { - return (nsrefcnt)1; + return (MozExternalRefCountType)1; } NS_IMPL_QUERY_INTERFACE1(nsCaseConversionImp2, nsICaseConversion) diff --git a/intl/unicharutil/src/nsCategoryImp.cpp b/intl/unicharutil/src/nsCategoryImp.cpp index a47a2e2a94b..a2d7a9705ab 100644 --- a/intl/unicharutil/src/nsCategoryImp.cpp +++ b/intl/unicharutil/src/nsCategoryImp.cpp @@ -10,14 +10,14 @@ NS_IMPL_QUERY_INTERFACE1(nsCategoryImp, nsIUGenCategory) -NS_IMETHODIMP_(nsrefcnt) nsCategoryImp::AddRef(void) +NS_IMETHODIMP_(MozExternalRefCountType) nsCategoryImp::AddRef(void) { - return nsrefcnt(1); + return MozExternalRefCountType(1); } -NS_IMETHODIMP_(nsrefcnt) nsCategoryImp::Release(void) +NS_IMETHODIMP_(MozExternalRefCountType) nsCategoryImp::Release(void) { - return nsrefcnt(1); + return MozExternalRefCountType(1); } nsCategoryImp* nsCategoryImp::GetInstance() diff --git a/ipc/testshell/XPCShellEnvironment.cpp b/ipc/testshell/XPCShellEnvironment.cpp index 1c0701de126..28f13e4b0e7 100644 --- a/ipc/testshell/XPCShellEnvironment.cpp +++ b/ipc/testshell/XPCShellEnvironment.cpp @@ -398,13 +398,13 @@ XPCShellEnvironment::ProcessFile(JSContext *cx, fprintf(stdout, "\n"); } -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) XPCShellDirProvider::AddRef() { return 2; } -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) XPCShellDirProvider::Release() { return 1; diff --git a/js/public/MemoryMetrics.h b/js/public/MemoryMetrics.h index e0c1c8a197a..e426b11d862 100644 --- a/js/public/MemoryMetrics.h +++ b/js/public/MemoryMetrics.h @@ -183,6 +183,7 @@ struct GCSizes macro(_, _, marker) \ macro(_, _, nurseryCommitted) \ macro(_, _, nurseryDecommitted) \ + macro(_, _, nurseryHugeSlots) \ macro(_, _, storeBufferVals) \ macro(_, _, storeBufferCells) \ macro(_, _, storeBufferSlots) \ diff --git a/js/public/RootingAPI.h b/js/public/RootingAPI.h index bc8a438ccd4..200f6a99676 100644 --- a/js/public/RootingAPI.h +++ b/js/public/RootingAPI.h @@ -152,11 +152,6 @@ template class PersistentRooted; /* This is exposing internal state of the GC for inlining purposes. */ JS_FRIEND_API(bool) isGCEnabled(); -#if defined(JS_DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE) -extern void -CheckStackRoots(JSContext *cx); -#endif - /* * JS::NullPtr acts like a nullptr pointer in contexts that require a Handle. * @@ -819,15 +814,6 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase Rooted **stack, *prev; #endif -#if defined(JS_DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE) - /* Has the rooting analysis ever scanned this Rooted's stack location? */ - friend void JS::CheckStackRoots(JSContext*); -#endif - -#ifdef JSGC_ROOT_ANALYSIS - bool scanned; -#endif - /* * |ptr| must be the last field in Rooted because the analysis treats all * Rooted as Rooted during the analysis. See bug 829372. @@ -861,81 +847,6 @@ class RootedBase JS::Handle as() const; }; -/* - * Mark a stack location as a root for the rooting analysis, without actually - * rooting it in release builds. This should only be used for stack locations - * of GC things that cannot be relocated by a garbage collection, and that - * are definitely reachable via another path. - */ -class SkipRoot -{ -#if defined(JS_DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE) - - SkipRoot **stack, *prev; - const uint8_t *start; - const uint8_t *end; - - template - void init(CX *cx, const T *ptr, size_t count) { - SkipRoot **head = &cx->skipGCRooters; - this->stack = head; - this->prev = *stack; - *stack = this; - this->start = (const uint8_t *) ptr; - this->end = this->start + (sizeof(T) * count); - } - - public: - ~SkipRoot() { - MOZ_ASSERT(*stack == this); - *stack = prev; - } - - SkipRoot *previous() { return prev; } - - bool contains(const uint8_t *v, size_t len) { - return v >= start && v + len <= end; - } - -#else /* JS_DEBUG && JSGC_ROOT_ANALYSIS */ - - template - void init(js::ContextFriendFields *cx, const T *ptr, size_t count) {} - - public: - ~SkipRoot() { - // An empty destructor is needed to avoid warnings from clang about - // unused local variables of this type. - } - -#endif /* JS_DEBUG && JSGC_ROOT_ANALYSIS */ - - template - SkipRoot(JSContext *cx, const T *ptr, size_t count = 1 - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - { - init(ContextFriendFields::get(cx), ptr, count); - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - - template - SkipRoot(ContextFriendFields *cx, const T *ptr, size_t count = 1 - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - { - init(cx, ptr, count); - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - - template - SkipRoot(PerThreadData *pt, const T *ptr, size_t count = 1 - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - { - init(PerThreadDataFriendFields::get(pt), ptr, count); - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -}; /* * RootedGeneric allows a class to instantiate its own Rooted type by @@ -958,15 +869,14 @@ class JS_PUBLIC_API(RootedGeneric) { public: JS::Rooted rooter; - SkipRoot skip; RootedGeneric(js::ContextFriendFields *cx) - : rooter(cx), skip(cx, rooter.address()) + : rooter(cx) { } RootedGeneric(js::ContextFriendFields *cx, const GCType &initial) - : rooter(cx, initial), skip(cx, rooter.address()) + : rooter(cx, initial) { } @@ -1287,17 +1197,6 @@ class PersistentRooted : private mozilla::LinkedListElement namespace js { -/* - * Hook for dynamic root analysis. Checks the native stack and poisons - * references to GC things which have not been rooted. - */ -inline void MaybeCheckStackRoots(JSContext *cx) -{ -#if defined(JS_DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE) - JS::CheckStackRoots(cx); -#endif -} - /* Base class for automatic read-only object rooting during compilation. */ class CompilerRootNode { diff --git a/js/public/Value.h b/js/public/Value.h index 6c21e4e1c79..1d931ca22d5 100644 --- a/js/public/Value.h +++ b/js/public/Value.h @@ -733,7 +733,7 @@ JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l) static inline bool JSVAL_IS_OBJECT_IMPL(jsval_layout l) { - MOZ_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_SHIFTED_TAG_OBJECT); + MOZ_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT); return l.asBits >= JSVAL_SHIFTED_TAG_OBJECT; } diff --git a/js/src/assembler/jit/ExecutableAllocatorPosix.cpp b/js/src/assembler/jit/ExecutableAllocatorPosix.cpp index 62c9d8cc234..3a66bfdffc2 100644 --- a/js/src/assembler/jit/ExecutableAllocatorPosix.cpp +++ b/js/src/assembler/jit/ExecutableAllocatorPosix.cpp @@ -43,14 +43,7 @@ size_t ExecutableAllocator::determinePageSize() ExecutablePool::Allocation ExecutableAllocator::systemAlloc(size_t n) { - void* allocation; -#ifdef JSGC_ROOT_ANALYSIS - do { -#endif - allocation = mmap(NULL, n, INITIAL_PROTECTION_FLAGS, MAP_PRIVATE | MAP_ANON, VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY, 0); -#ifdef JSGC_ROOT_ANALYSIS - } while (allocation && JS::IsPoisonedPtr(allocation)); -#endif + void *allocation = mmap(NULL, n, INITIAL_PROTECTION_FLAGS, MAP_PRIVATE | MAP_ANON, VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY, 0); if (allocation == MAP_FAILED) allocation = NULL; ExecutablePool::Allocation alloc = { reinterpret_cast(allocation), n }; @@ -58,7 +51,7 @@ ExecutablePool::Allocation ExecutableAllocator::systemAlloc(size_t n) } void ExecutableAllocator::systemRelease(const ExecutablePool::Allocation& alloc) -{ +{ int result = munmap(alloc.pages, alloc.size); ASSERT_UNUSED(result, !result); } diff --git a/js/src/builtin/Intl.cpp b/js/src/builtin/Intl.cpp index 29dda165de0..a6a12b6a362 100644 --- a/js/src/builtin/Intl.cpp +++ b/js/src/builtin/Intl.cpp @@ -1290,7 +1290,6 @@ NewUNumberFormat(JSContext *cx, HandleObject numberFormat) bool uUseGrouping = true; // Sprinkle appropriate rooting flavor over things the GC might care about. - SkipRoot skip(cx, &uCurrency); RootedString currency(cx); // We don't need to look at numberingSystem - it can only be set via @@ -1783,7 +1782,6 @@ js::intl_patternForSkeleton(JSContext *cx, unsigned argc, Value *vp) const jschar *skeleton = JS_GetStringCharsZ(cx, jsskeleton); if (!skeleton) return false; - SkipRoot skip(cx, &skeleton); uint32_t skeletonLen = u_strlen(JSCharToUChar(skeleton)); UErrorCode status = U_ZERO_ERROR; @@ -1845,9 +1843,6 @@ NewUDateFormat(JSContext *cx, HandleObject dateTimeFormat) const UChar *uPattern = nullptr; uint32_t uPatternLength = 0; - SkipRoot skipTimeZone(cx, &uTimeZone); - SkipRoot skipPattern(cx, &uPattern); - // We don't need to look at calendar and numberingSystem - they can only be // set via the Unicode locale extension and are therefore already set on // locale. diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp index a54a5b505f5..7abda757c3c 100644 --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -102,8 +102,10 @@ ExecuteRegExpImpl(JSContext *cx, RegExpStatics *res, RegExpShared &re, } else { /* Vector of MatchPairs provided: execute full regexp. */ status = re.execute(cx, chars, length, lastIndex, *matches.u.pairs); - if (status == RegExpRunStatus_Success && res) - res->updateFromMatchPairs(cx, input, *matches.u.pairs); + if (status == RegExpRunStatus_Success && res) { + if (!res->updateFromMatchPairs(cx, input, *matches.u.pairs)) + return RegExpRunStatus_Error; + } } return status; diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 551a673622b..f7767a96930 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -43,13 +43,8 @@ GetBuildConfiguration(JSContext *cx, unsigned argc, jsval *vp) RootedObject info(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr())); if (!info) return false; - RootedValue value(cx); -#ifdef JSGC_ROOT_ANALYSIS - value = BooleanValue(true); -#else - value = BooleanValue(false); -#endif + RootedValue value(cx, BooleanValue(false)); if (!JS_SetProperty(cx, info, "rooting-analysis", value)) return false; @@ -980,6 +975,9 @@ EnableSPSProfilingAssertions(JSContext *cx, unsigned argc, jsval *vp) static ProfileEntry stack[1000]; static uint32_t stack_size = 0; + // Disable before re-enabling; see the assertion in |SPSProfiler::setProfilingStack|. + if (cx->runtime()->spsProfiler.installed()) + cx->runtime()->spsProfiler.enable(false); SetRuntimeProfilingStack(cx->runtime(), stack, &stack_size, 1000); cx->runtime()->spsProfiler.enableSlowAssertions(args[0].toBoolean()); cx->runtime()->spsProfiler.enable(true); diff --git a/js/src/configure.in b/js/src/configure.in index dfdae762014..4071ec5d656 100644 --- a/js/src/configure.in +++ b/js/src/configure.in @@ -3246,25 +3246,18 @@ fi dnl ======================================================== dnl = Use generational GC dnl ======================================================== -MOZ_ARG_ENABLE_BOOL(gcgenerational, -[ --enable-gcgenerational Enable generational GC], - JSGC_GENERATIONAL=1, - JSGC_GENERATIONAL= ) +dnl Use generational GC by default in all shell builds. The top-level mozilla +dnl configure.in will configure SpiderMonkey with --disable-gcgenerational as +dnl needed on a per-platform basis. +JSGC_GENERATIONAL=1 +MOZ_ARG_DISABLE_BOOL(gcgenerational, +[ --disable-gcgenerational Disable generational GC], + JSGC_GENERATIONAL= , + JSGC_GENERATIONAL=1 ) if test -n "$JSGC_GENERATIONAL"; then AC_DEFINE(JSGC_GENERATIONAL) fi -dnl ======================================================== -dnl = Perform moving GC stack rooting analysis -dnl ======================================================== -MOZ_ARG_ENABLE_BOOL(root-analysis, -[ --enable-root-analysis Enable moving GC stack root analysis], - JSGC_ROOT_ANALYSIS=1, - JSGC_ROOT_ANALYSIS= ) -if test -n "$JSGC_ROOT_ANALYSIS"; then - AC_DEFINE(JSGC_ROOT_ANALYSIS) -fi - dnl ======================================================== dnl = Use exact stack rooting for GC dnl ======================================================== diff --git a/js/src/ds/BitArray.h b/js/src/ds/BitArray.h index 92471e7e71d..b39ffae2869 100644 --- a/js/src/ds/BitArray.h +++ b/js/src/ds/BitArray.h @@ -16,16 +16,22 @@ namespace js { template -class BitArray { +class BitArray +{ private: static const size_t bitsPerElement = sizeof(uintptr_t) * CHAR_BIT; - static const size_t numSlots = - nbits / bitsPerElement + (nbits % bitsPerElement == 0 ? 0 : 1); + static const size_t numSlots = nbits / bitsPerElement + (nbits % bitsPerElement == 0 ? 0 : 1); + static const size_t paddingBits = (numSlots * bitsPerElement) - nbits; + static_assert(paddingBits < bitsPerElement, "More padding bits than expected."); + static const uintptr_t paddingMask = uintptr_t(-1) >> paddingBits; + uintptr_t map[numSlots]; public: void clear(bool value) { memset(map, value ? 0xFF : 0, sizeof(map)); + if (value) + map[numSlots - 1] &= paddingMask; } inline bool get(size_t offset) const { @@ -34,13 +40,13 @@ class BitArray { return map[index] & mask; } - inline void set(size_t offset) { + void set(size_t offset) { uintptr_t index, mask; getMarkWordAndMask(offset, &index, &mask); map[index] |= mask; } - inline void unset(size_t offset) { + void unset(size_t offset) { uintptr_t index, mask; getMarkWordAndMask(offset, &index, &mask); map[index] &= ~mask; diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index 57e7216d25d..3556691c748 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -188,7 +188,6 @@ frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject sco SourceCompressionTask *extraSct /* = nullptr */) { RootedString source(cx, source_); - SkipRoot skip(cx, &chars); #if JS_TRACE_LOGGING js::AutoTraceLog logger(js::TraceLogging::defaultLogger(), @@ -507,7 +506,6 @@ CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, const ReadOnlyComp // FIXME: make Function pass in two strings and parse them as arguments and // ProgramElements respectively. - SkipRoot skip(cx, &chars); MaybeCallSourceHandler(cx, options, chars, length); diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index 5364080f952..c59912d2f7b 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -278,10 +278,7 @@ TokenStream::TokenStream(ExclusiveContext *cx, const ReadOnlyCompileOptions &opt tokenbuf(cx), cx(cx), originPrincipals(options.originPrincipals(cx)), - strictModeGetter(smg), - tokenSkip(cx, &tokens), - linebaseSkip(cx, &linebase), - prevLinebaseSkip(cx, &prevLinebase) + strictModeGetter(smg) { // The caller must ensure that a reference is held on the supplied principals // throughout compilation. diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index 329dc4c3167..85b00192282 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -747,8 +747,7 @@ class MOZ_STACK_CLASS TokenStream class TokenBuf { public: TokenBuf(ExclusiveContext *cx, const jschar *buf, size_t length) - : base_(buf), limit_(buf + length), ptr(buf), - skipBase(cx, &base_), skipLimit(cx, &limit_), skipPtr(cx, &ptr) + : base_(buf), limit_(buf + length), ptr(buf) { } bool hasRawChars() const { @@ -827,9 +826,6 @@ class MOZ_STACK_CLASS TokenStream const jschar *base_; // base of buffer const jschar *limit_; // limit for quick bounds check const jschar *ptr; // next char to get - - // We are not yet moving strings - SkipRoot skipBase, skipLimit, skipPtr; }; TokenKind getTokenInternal(Modifier modifier); @@ -898,15 +894,6 @@ class MOZ_STACK_CLASS TokenStream ExclusiveContext *const cx; JSPrincipals *const originPrincipals; StrictModeGetter *strictModeGetter; // used to test for strict mode - - // The tokens array stores pointers to JSAtoms. These are rooted by the - // atoms table using AutoKeepAtoms in the Parser. This SkipRoot tells the - // exact rooting analysis to ignore the atoms in the tokens array. - SkipRoot tokenSkip; - - // Bug 846011 - SkipRoot linebaseSkip; - SkipRoot prevLinebaseSkip; }; // Steal one JSREPORT_* bit (see jsapi.h) to tell that arguments to the error diff --git a/js/src/gc/GCInternals.h b/js/src/gc/GCInternals.h index 02ca149c5be..2ee1793f503 100644 --- a/js/src/gc/GCInternals.h +++ b/js/src/gc/GCInternals.h @@ -96,11 +96,6 @@ class IncrementalSafety IncrementalSafety IsIncrementalGCSafe(JSRuntime *rt); -#ifdef JSGC_ROOT_ANALYSIS -void * -GetAddressableGCThing(JSRuntime *rt, uintptr_t w); -#endif - #ifdef JS_GC_ZEAL void StartVerifyPreBarriers(JSRuntime *rt); diff --git a/js/src/gc/Heap.h b/js/src/gc/Heap.h index 286246d024f..47ed8f874c8 100644 --- a/js/src/gc/Heap.h +++ b/js/src/gc/Heap.h @@ -18,6 +18,7 @@ #include "jsutil.h" #include "ds/BitArray.h" +#include "gc/Memory.h" #include "js/HeapAPI.h" struct JSCompartment; @@ -808,6 +809,16 @@ struct Chunk static Chunk *allocate(JSRuntime *rt); + void decommitAllArenas(JSRuntime *rt) { + decommittedArenas.clear(true); + MarkPagesUnused(rt, &arenas[0], ArenasPerChunk * ArenaSize); + + info.freeArenasHead = nullptr; + info.lastDecommittedArenaOffset = 0; + info.numArenasFree = ArenasPerChunk; + info.numArenasFreeCommitted = 0; + } + /* Must be called with the GC lock taken. */ static inline void release(JSRuntime *rt, Chunk *chunk); static inline void releaseList(JSRuntime *rt, Chunk *chunkListHead); diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp index ad37f309357..4c3a6a5b1d6 100644 --- a/js/src/gc/Nursery.cpp +++ b/js/src/gc/Nursery.cpp @@ -52,19 +52,6 @@ js::Nursery::init() return false; void *heap = MapAlignedPages(runtime(), NurserySize, Alignment); -#ifdef JSGC_ROOT_ANALYSIS - // Our poison pointers are not guaranteed to be invalid on 64-bit - // architectures, and often are valid. We can't just reserve the full - // poison range, because it might already have been taken up by something - // else (shared library, previous allocation). So we'll just loop and - // discard poison pointers until we get something valid. - // - // This leaks all of these poisoned pointers. It would be better if they - // were marked as uncommitted, but it's a little complicated to avoid - // clobbering pre-existing unrelated mappings. - while (IsPoisonedPtr(heap) || IsPoisonedPtr((void*)(uintptr_t(heap) + NurserySize))) - heap = MapAlignedPages(runtime(), NurserySize, Alignment); -#endif if (!heap) return false; diff --git a/js/src/gc/Nursery.h b/js/src/gc/Nursery.h index 7b248cb01b6..ed090d4cd1a 100644 --- a/js/src/gc/Nursery.h +++ b/js/src/gc/Nursery.h @@ -125,8 +125,19 @@ class Nursery /* Forward a slots/elements pointer stored in an Ion frame. */ void forwardBufferPointer(HeapSlot **pSlotsElems); - size_t sizeOfHeapCommitted() { return numActiveChunks_ * gc::ChunkSize; } - size_t sizeOfHeapDecommitted() { return (NumNurseryChunks - numActiveChunks_) * gc::ChunkSize; } + size_t sizeOfHeapCommitted() const { + return numActiveChunks_ * gc::ChunkSize; + } + size_t sizeOfHeapDecommitted() const { + return (NumNurseryChunks - numActiveChunks_) * gc::ChunkSize; + } + size_t sizeOfHugeSlots(mozilla::MallocSizeOf mallocSizeOf) const { + size_t total = 0; + for (HugeSlotsSet::Range r = hugeSlots.all(); !r.empty(); r.popFront()) + total += mallocSizeOf(r.front()); + total += hugeSlots.sizeOfExcludingThis(mallocSizeOf); + return total; + } private: /* diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index 3363f8a43ac..ba4f54cabc3 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -186,21 +186,6 @@ IsAddressableGCThing(JSRuntime *rt, uintptr_t w, return CGCT_VALID; } -#ifdef JSGC_ROOT_ANALYSIS -void * -js::gc::GetAddressableGCThing(JSRuntime *rt, uintptr_t w) -{ - void *thing; - ArenaHeader *aheader; - AllocKind thingKind; - ConservativeGCTest status = - IsAddressableGCThing(rt, w, false, &thingKind, &aheader, &thing); - if (status != CGCT_VALID) - return nullptr; - return thing; -} -#endif - /* * Returns CGCT_VALID and mark it if the w can be a live GC thing and sets * thingKind accordingly. Otherwise returns the reason for rejection. diff --git a/js/src/gc/Verifier.cpp b/js/src/gc/Verifier.cpp index f521d757262..7cb15ad4e30 100644 --- a/js/src/gc/Verifier.cpp +++ b/js/src/gc/Verifier.cpp @@ -24,287 +24,6 @@ using namespace js; using namespace js::gc; using namespace mozilla; -#if defined(DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE) -# if JS_STACK_GROWTH_DIRECTION > 0 -# error "Root analysis is only supported on a descending stack." -# endif - -template -bool -CheckNonAddressThing(uintptr_t *w, Rooted *rootp) -{ - return w >= (uintptr_t*)rootp->address() && w < (uintptr_t*)(rootp->address() + 1); -} - -static MOZ_ALWAYS_INLINE bool -CheckStackRootThing(uintptr_t *w, Rooted *rootp, ThingRootKind kind) -{ - if (kind == THING_ROOT_BINDINGS) - return CheckNonAddressThing(w, reinterpret_cast *>(rootp)); - - if (kind == THING_ROOT_PROPERTY_DESCRIPTOR) - return CheckNonAddressThing(w, reinterpret_cast *>(rootp)); - - if (kind == THING_ROOT_VALUE) - return CheckNonAddressThing(w, reinterpret_cast *>(rootp)); - - return rootp->address() == static_cast(w); -} - -struct Rooter { - Rooted *rooter; - ThingRootKind kind; -}; - -static void -CheckStackRoot(JSRuntime *rt, uintptr_t *w, Rooter *begin, Rooter *end) -{ - /* Mark memory as defined for valgrind, as in MarkWordConservatively. */ -#ifdef MOZ_VALGRIND - VALGRIND_MAKE_MEM_DEFINED(&w, sizeof(w)); -#endif - - void *thing = GetAddressableGCThing(rt, *w); - if (!thing) - return; - - /* Don't check atoms as these will never be subject to generational collection. */ - if (rt->isAtomsZone(static_cast(thing)->tenuredZone())) - return; - - /* - * Note that |thing| may be in a free list (InFreeList(aheader, thing)), - * but we can skip that check because poisoning the pointer can't hurt; the - * pointer still cannot be used for a non-gcthing. - */ - - for (Rooter *p = begin; p != end; p++) { - if (CheckStackRootThing(w, p->rooter, p->kind)) - return; - } - - SkipRoot *skip = TlsPerThreadData.get()->skipGCRooters; - while (skip) { - if (skip->contains(reinterpret_cast(w), sizeof(w))) - return; - skip = skip->previous(); - } - for (ContextIter cx(rt); !cx.done(); cx.next()) { - skip = cx->skipGCRooters; - while (skip) { - if (skip->contains(reinterpret_cast(w), sizeof(w))) - return; - skip = skip->previous(); - } - } - - /* - * Only poison the last byte in the word. It is easy to get accidental - * collisions when a value that does not occupy a full word is used to - * overwrite a now-dead GC thing pointer. In this case we want to avoid - * damaging the smaller value. - */ - JS::PoisonPtr(w); -} - -static void -CheckStackRootsRange(JSRuntime *rt, uintptr_t *begin, uintptr_t *end, Rooter *rbegin, Rooter *rend) -{ - JS_ASSERT(begin <= end); - for (uintptr_t *i = begin; i != end; ++i) - CheckStackRoot(rt, i, rbegin, rend); -} - -static void -CheckStackRootsRangeAndSkipJit(JSRuntime *rt, uintptr_t *begin, uintptr_t *end, Rooter *rbegin, Rooter *rend) -{ - /* - * Regions of the stack between Ion activiations are marked exactly through - * a different mechanism. We need to skip these regions when checking the - * stack so that we do not poison IonMonkey's things. - */ - uintptr_t *i = begin; - -#if defined(JS_ION) - for (jit::JitActivationIterator iter(rt); !iter.done(); ++iter) { - uintptr_t *jitMin, *jitEnd; - iter.jitStackRange(jitMin, jitEnd); - - uintptr_t *upto = Min(jitMin, end); - if (upto > i) - CheckStackRootsRange(rt, i, upto, rbegin, rend); - else - break; - i = jitEnd; - } -#endif - - /* The topmost Ion activiation may be beyond our prior top. */ - if (i < end) - CheckStackRootsRange(rt, i, end, rbegin, rend); -} - -static int -CompareRooters(const void *vpA, const void *vpB) -{ - const Rooter *a = static_cast(vpA); - const Rooter *b = static_cast(vpB); - // There should be no duplicates, and we wouldn't care about their order anyway. - return (a->rooter < b->rooter) ? -1 : 1; -} - -/* - * In the pathological cases that dominate much of the test case runtime, - * rooting analysis spends tons of time scanning the stack during a tight-ish - * loop. Since statically, everything is either rooted or it isn't, these scans - * are almost certain to be worthless. Detect these cases by checking whether - * the addresses of the top several rooters in the stack are recurring. Note - * that there may be more than one CheckRoots call within the loop, so we may - * alternate between a couple of stacks rather than just repeating the same one - * over and over, so we need more than a depth-1 memory. - */ -static bool -SuppressCheckRoots(js::Vector &rooters) -{ - static const unsigned int NumStackMemories = 6; - static const size_t StackCheckDepth = 10; - - static uint32_t stacks[NumStackMemories]; - static unsigned int numMemories = 0; - static unsigned int oldestMemory = 0; - - // Ugh. Sort the rooters. This should really be an O(n) rank selection - // followed by a sort. Interestingly, however, the overall scan goes a bit - // *faster* with this sort. Better branch prediction of the later - // partitioning pass, perhaps. - qsort(rooters.begin(), rooters.length(), sizeof(Rooter), CompareRooters); - - // Forward-declare a variable so its address can be used to mark the - // current top of the stack. - unsigned int pos; - - // Compute the hash of the current stack. - uint32_t hash = HashGeneric(&pos); - for (unsigned int i = 0; i < Min(StackCheckDepth, rooters.length()); i++) - hash = AddToHash(hash, rooters[rooters.length() - i - 1].rooter); - - // Scan through the remembered stacks to find the current stack. - for (pos = 0; pos < numMemories; pos++) { - if (stacks[pos] == hash) { - // Skip this check. Technically, it is incorrect to not update the - // LRU queue position, but it'll cost us at most one extra check - // for every time a hot stack falls out of the window. - return true; - } - } - - // Replace the oldest remembered stack with our current stack. - stacks[oldestMemory] = hash; - oldestMemory = (oldestMemory + 1) % NumStackMemories; - if (numMemories < NumStackMemories) - numMemories++; - - return false; -} - -static void -GatherRooters(js::Vector &rooters, - Rooted **thingGCRooters, - unsigned thingRootKind) -{ - Rooted *rooter = thingGCRooters[thingRootKind]; - while (rooter) { - Rooter r = { rooter, ThingRootKind(thingRootKind) }; - JS_ALWAYS_TRUE(rooters.append(r)); - rooter = rooter->previous(); - } -} - -void -JS::CheckStackRoots(JSContext *cx) -{ - JSRuntime *rt = cx->runtime(); - - if (rt->gcZeal_ != ZealStackRootingValue) - return; - - // GCs can't happen when analysis/inference/compilation are active. - if (cx->compartment()->activeAnalysis) - return; - - if (rt->mainThread.suppressGC) - return; - - // Can switch to the atoms compartment during analysis. - if (IsAtomsCompartment(cx->compartment())) { - for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) { - if (c.get()->activeAnalysis) - return; - } - } - - AutoCopyFreeListToArenas copy(rt, WithAtoms); - - ConservativeGCData *cgcd = &rt->conservativeGC; - cgcd->recordStackTop(); - - JS_ASSERT(cgcd->hasStackToScan()); - uintptr_t *stackMin, *stackEnd; - stackMin = cgcd->nativeStackTop + 1; - stackEnd = reinterpret_cast(rt->nativeStackBase); - JS_ASSERT(stackMin <= stackEnd); - - // Gather up all of the rooters - js::Vector rooters; - for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) { - for (ContextIter cx(rt); !cx.done(); cx.next()) { - GatherRooters(rooters, cx->thingGCRooters, i); - } - - GatherRooters(rooters, rt->mainThread.thingGCRooters, i); - } - - if (SuppressCheckRoots(rooters)) - return; - - // Truncate stackEnd to just after the address of the youngest - // already-scanned rooter on the stack, to avoid re-scanning the rest of - // the stack. - void *firstScanned = nullptr; - for (Rooter *p = rooters.begin(); p != rooters.end(); p++) { - if (p->rooter->scanned) { - uintptr_t *addr = reinterpret_cast(p->rooter); - if (stackEnd > addr) { - stackEnd = addr; - firstScanned = p->rooter; - } - } - } - - // Partition the stack by the already-scanned start address. Put everything - // that needs to be searched at the end of the vector. - Rooter *firstToScan = rooters.begin(); - if (firstScanned) { - for (Rooter *p = rooters.begin(); p != rooters.end(); p++) { - if (p->rooter >= firstScanned) { - Swap(*firstToScan, *p); - ++firstToScan; - } - } - } - - CheckStackRootsRangeAndSkipJit(rt, stackMin, stackEnd, firstToScan, rooters.end()); - CheckStackRootsRange(rt, cgcd->registerSnapshot.words, - ArrayEnd(cgcd->registerSnapshot.words), - firstToScan, rooters.end()); - - // Mark all rooters as scanned. - for (Rooter *p = rooters.begin(); p != rooters.end(); p++) - p->rooter->scanned = true; -} - -#endif /* DEBUG && JS_GC_ZEAL && JSGC_ROOT_ANALYSIS && !JS_THREADSAFE */ - #ifdef JS_GC_ZEAL /* diff --git a/js/src/jit-test/tests/profiler/enterjit-osr-disabling-earlyret.js b/js/src/jit-test/tests/profiler/enterjit-osr-disabling-earlyret.js new file mode 100644 index 00000000000..2b74e7cc578 --- /dev/null +++ b/js/src/jit-test/tests/profiler/enterjit-osr-disabling-earlyret.js @@ -0,0 +1,13 @@ +setJitCompilerOption("baseline.usecount.trigger", 10); +setJitCompilerOption("ion.usecount.trigger", 20); + +enableSPSProfilingAssertions(true); +(function() { + var n = 50; + while (n--) { + disableSPSProfiling(); + if (!n) + return; + enableSPSProfilingAssertions(true); + } +})(); diff --git a/js/src/jit-test/tests/profiler/enterjit-osr-disabling.js b/js/src/jit-test/tests/profiler/enterjit-osr-disabling.js new file mode 100644 index 00000000000..56ad70b8e9b --- /dev/null +++ b/js/src/jit-test/tests/profiler/enterjit-osr-disabling.js @@ -0,0 +1,9 @@ +setJitCompilerOption("baseline.usecount.trigger", 10); +setJitCompilerOption("ion.usecount.trigger", 20); + +enableSPSProfilingAssertions(true); +(function() { + disableSPSProfiling(); + var n = 50; + while (n--); +})(); diff --git a/js/src/jit-test/tests/profiler/enterjit-osr-enabling-earlyret.js b/js/src/jit-test/tests/profiler/enterjit-osr-enabling-earlyret.js new file mode 100644 index 00000000000..8f3752db6f0 --- /dev/null +++ b/js/src/jit-test/tests/profiler/enterjit-osr-enabling-earlyret.js @@ -0,0 +1,12 @@ +setJitCompilerOption("baseline.usecount.trigger", 10); +setJitCompilerOption("ion.usecount.trigger", 20); + +(function() { + var n = 50; + while (n--) { + enableSPSProfilingAssertions(true); + if (!n) + return; + disableSPSProfiling(); + } +})(); diff --git a/js/src/jit-test/tests/profiler/enterjit-osr-enabling.js b/js/src/jit-test/tests/profiler/enterjit-osr-enabling.js new file mode 100644 index 00000000000..43fbc681f40 --- /dev/null +++ b/js/src/jit-test/tests/profiler/enterjit-osr-enabling.js @@ -0,0 +1,8 @@ +setJitCompilerOption("baseline.usecount.trigger", 10); +setJitCompilerOption("ion.usecount.trigger", 20); + +(function() { + enableSPSProfilingAssertions(true); + var n = 50; + while (n--); +})(); diff --git a/js/src/jit-test/tests/profiler/enterjit-osr.js b/js/src/jit-test/tests/profiler/enterjit-osr.js new file mode 100644 index 00000000000..0b8373e7766 --- /dev/null +++ b/js/src/jit-test/tests/profiler/enterjit-osr.js @@ -0,0 +1,8 @@ +setJitCompilerOption("baseline.usecount.trigger", 10); +setJitCompilerOption("ion.usecount.trigger", 20); + +enableSPSProfilingAssertions(true); +(function() { + var n = 50; + while (n--); +})(); diff --git a/js/src/jit/Bailouts.cpp b/js/src/jit/Bailouts.cpp index a55bd49e64b..487a7aa033e 100644 --- a/js/src/jit/Bailouts.cpp +++ b/js/src/jit/Bailouts.cpp @@ -37,10 +37,11 @@ using namespace js::jit; // bailed out frame. SnapshotIterator::SnapshotIterator(const IonBailoutIterator &iter) - : SnapshotReader(iter.ionScript()->snapshots(), - iter.snapshotOffset(), - iter.ionScript()->snapshotsRVATableSize(), - iter.ionScript()->snapshotsListSize()), + : snapshot_(iter.ionScript()->snapshots(), + iter.snapshotOffset(), + iter.ionScript()->snapshotsRVATableSize(), + iter.ionScript()->snapshotsListSize()), + recover_(snapshot_), fp_(iter.jsFrame()), machine_(iter.machineState()), ionScript_(iter.ionScript()) diff --git a/js/src/jit/BaselineFrame.cpp b/js/src/jit/BaselineFrame.cpp index 5dd24c96cef..97f71d5066c 100644 --- a/js/src/jit/BaselineFrame.cpp +++ b/js/src/jit/BaselineFrame.cpp @@ -178,8 +178,18 @@ BaselineFrame::initForOsr(InterpreterFrame *fp, uint32_t numStackValues) if (fp->hasReturnValue()) setReturnValue(fp->returnValue()); - if (fp->hasPushedSPSFrame()) + // If the interpreter pushed an SPS frame when it entered the function, the + // interpreter will pop it after the OSR trampoline returns. In order for + // the Baseline frame to have its SPS flag set, it must have its own SPS + // frame, which the Baseline code will pop on return. Note that the + // profiler may have been enabled or disabled after the function was entered + // but before OSR. + JSContext *cx = GetJSContextFromJitCode(); + SPSProfiler *p = &(cx->runtime()->spsProfiler); + if (p->enabled()) { + p->enter(fp->script(), fp->maybeFun()); flags_ |= BaselineFrame::HAS_PUSHED_SPS_FRAME; + } frameSize_ = BaselineFrame::FramePointerOffset + BaselineFrame::Size() + @@ -190,7 +200,6 @@ BaselineFrame::initForOsr(InterpreterFrame *fp, uint32_t numStackValues) for (uint32_t i = 0; i < numStackValues; i++) *valueSlot(i) = fp->slots()[i]; - JSContext *cx = GetJSContextFromJitCode(); if (cx->compartment()->debugMode()) { // In debug mode, update any Debugger.Frame objects for the // InterpreterFrame to point to the BaselineFrame. diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index ee660cd2a7d..827b7f6b1fe 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -1212,7 +1212,6 @@ GetPropertyIC::tryAttachNative(JSContext *cx, IonScript *ion, HandleObject obj, *emitted = true; MacroAssembler masm(cx, ion, script_, pc_); - SkipRoot skip(cx, &masm); RepatchStubAppender attacher(*this); const char *attachKind; @@ -2994,7 +2993,6 @@ GetElementIC::attachGetProp(JSContext *cx, IonScript *ion, HandleObject obj, Label failures; MacroAssembler masm(cx, ion); - SkipRoot skip(cx, &masm); // Ensure the index is a string. ValueOperand val = index().reg().valueReg(); diff --git a/js/src/jit/IonFrameIterator.h b/js/src/jit/IonFrameIterator.h index 62d986d5586..9de60268d44 100644 --- a/js/src/jit/IonFrameIterator.h +++ b/js/src/jit/IonFrameIterator.h @@ -246,8 +246,10 @@ class IonBailoutIterator; // Reads frame information in snapshot-encoding order (that is, outermost frame // to innermost frame). -class SnapshotIterator : public SnapshotReader +class SnapshotIterator { + SnapshotReader snapshot_; + RecoverReader recover_; IonJSFrameLayout *fp_; MachineState machine_; IonScript *ionScript_; @@ -279,16 +281,63 @@ class SnapshotIterator : public SnapshotReader void warnUnreadableAllocation(); public: + // Handle iterating over RValueAllocations of the snapshots. + inline RValueAllocation readAllocation() { + MOZ_ASSERT(moreAllocations()); + return snapshot_.readAllocation(); + } + Value skip() { + readAllocation(); + return UndefinedValue(); + } + + inline uint32_t allocations() const { + return recover_.allocations(); + } + inline bool moreAllocations() const { + return recover_.moreAllocations(snapshot_); + } + + public: + // Exhibits frame properties contained in the snapshot. + inline uint32_t pcOffset() const { + return recover_.pcOffset(); + } + inline bool resumeAfter() const { + // Inline frames are inlined on calls, which are considered as being + // resumed on the Call as baseline will push the pc once we return from + // the call. + if (moreFrames()) + return false; + return snapshot_.resumeAfter(); + } + inline BailoutKind bailoutKind() const { + return snapshot_.bailoutKind(); + } + + public: + // Handle iterating over frames of the snapshots. + inline void nextFrame() { + // Reuse the Snapshot buffer. + recover_.nextFrame(snapshot_); + } + inline bool moreFrames() const { + return recover_.moreFrames(); + } + inline uint32_t frameCount() const { + return recover_.frameCount(); + } + + public: + // Connect all informations about the current script in order to recover the + // content of baseline frames. + SnapshotIterator(IonScript *ionScript, SnapshotOffset snapshotOffset, IonJSFrameLayout *fp, const MachineState &machine); SnapshotIterator(const IonFrameIterator &iter); SnapshotIterator(const IonBailoutIterator &iter); SnapshotIterator(); - Value skip() { - readAllocation(); - return UndefinedValue(); - } Value read() { return allocationValue(readAllocation()); } diff --git a/js/src/jit/IonFrames.cpp b/js/src/jit/IonFrames.cpp index f6b19d0b6a6..b64ce84897c 100644 --- a/js/src/jit/IonFrames.cpp +++ b/js/src/jit/IonFrames.cpp @@ -1291,10 +1291,11 @@ OsiIndex::returnPointDisplacement() const SnapshotIterator::SnapshotIterator(IonScript *ionScript, SnapshotOffset snapshotOffset, IonJSFrameLayout *fp, const MachineState &machine) - : SnapshotReader(ionScript->snapshots(), - snapshotOffset, - ionScript->snapshotsRVATableSize(), - ionScript->snapshotsListSize()), + : snapshot_(ionScript->snapshots(), + snapshotOffset, + ionScript->snapshotsRVATableSize(), + ionScript->snapshotsListSize()), + recover_(snapshot_), fp_(fp), machine_(machine), ionScript_(ionScript) @@ -1303,10 +1304,11 @@ SnapshotIterator::SnapshotIterator(IonScript *ionScript, SnapshotOffset snapshot } SnapshotIterator::SnapshotIterator(const IonFrameIterator &iter) - : SnapshotReader(iter.ionScript()->snapshots(), - iter.osiIndex()->snapshotOffset(), - iter.ionScript()->snapshotsRVATableSize(), - iter.ionScript()->snapshotsListSize()), + : snapshot_(iter.ionScript()->snapshots(), + iter.osiIndex()->snapshotOffset(), + iter.ionScript()->snapshotsRVATableSize(), + iter.ionScript()->snapshotsListSize()), + recover_(snapshot_), fp_(iter.jsFrame()), machine_(iter.machineState()), ionScript_(iter.ionScript()) @@ -1314,7 +1316,8 @@ SnapshotIterator::SnapshotIterator(const IonFrameIterator &iter) } SnapshotIterator::SnapshotIterator() - : SnapshotReader(nullptr, 0, 0, 0), + : snapshot_(nullptr, 0, 0, 0), + recover_(snapshot_), fp_(nullptr), ionScript_(nullptr) { diff --git a/js/src/jit/IonMacroAssembler.cpp b/js/src/jit/IonMacroAssembler.cpp index 0acf8baebc2..f2ee98746e8 100644 --- a/js/src/jit/IonMacroAssembler.cpp +++ b/js/src/jit/IonMacroAssembler.cpp @@ -1904,3 +1904,54 @@ MacroAssembler::branchEqualTypeIfNeeded(MIRType type, MDefinition *maybeDef, Reg } } } + + +// If a pseudostack frame has this as its label, its stack pointer +// field points to the registers saved on entry to JIT code. A native +// stack unwinder could use that information to continue unwinding +// past that point. +const char MacroAssembler::enterJitLabel[] = "EnterJIT"; + +// Creates an enterJIT pseudostack frame, as described above. Pushes +// a word to the stack to indicate whether this was done. |framePtr| is +// the pointer to the machine-dependent saved state. +void +MacroAssembler::spsMarkJit(SPSProfiler *p, Register framePtr, Register temp) +{ + Label spsNotEnabled; + uint32_t *enabledAddr = p->addressOfEnabled(); + load32(AbsoluteAddress(enabledAddr), temp); + push(temp); // +4: Did we push an sps frame. + branchTest32(Assembler::Equal, temp, temp, &spsNotEnabled); + + Label stackFull; + // We always need the "safe" versions, because these are used in trampolines + // and won't be regenerated when SPS state changes. + spsProfileEntryAddressSafe(p, 0, temp, &stackFull); + + storePtr(ImmPtr(enterJitLabel), Address(temp, ProfileEntry::offsetOfString())); + storePtr(framePtr, Address(temp, ProfileEntry::offsetOfStackAddress())); + storePtr(ImmWord(uintptr_t(0)), Address(temp, ProfileEntry::offsetOfScript())); + store32(Imm32(ProfileEntry::NullPCIndex), Address(temp, ProfileEntry::offsetOfPCIdx())); + + /* Always increment the stack size, whether or not we actually pushed. */ + bind(&stackFull); + loadPtr(AbsoluteAddress(p->addressOfSizePointer()), temp); + add32(Imm32(1), Address(temp, 0)); + + bind(&spsNotEnabled); +} + +// Pops the word pushed by spsMarkJit and, if spsMarkJit pushed an SPS +// frame, pops it. +void +MacroAssembler::spsUnmarkJit(SPSProfiler *p, Register temp) +{ + Label spsNotEnabled; + pop(temp); // -4: Was the profiler enabled. + branchTest32(Assembler::Equal, temp, temp, &spsNotEnabled); + + spsPopFrameSafe(p, temp); + + bind(&spsNotEnabled); +} diff --git a/js/src/jit/IonMacroAssembler.h b/js/src/jit/IonMacroAssembler.h index 7e889d447db..7e8dccab556 100644 --- a/js/src/jit/IonMacroAssembler.h +++ b/js/src/jit/IonMacroAssembler.h @@ -1021,7 +1021,6 @@ class MacroAssembler : public MacroAssemblerSpecific } public: - // These functions are needed by the IonInstrumentation interface defined in // vm/SPSProfiler.h. They will modify the pseudostack provided to SPS to // perform the actual instrumentation. @@ -1092,6 +1091,10 @@ class MacroAssembler : public MacroAssemblerSpecific add32(Imm32(-1), Address(temp, 0)); } + static const char enterJitLabel[]; + void spsMarkJit(SPSProfiler *p, Register framePtr, Register temp); + void spsUnmarkJit(SPSProfiler *p, Register temp); + void loadBaselineOrIonRaw(Register script, Register dest, ExecutionMode mode, Label *failure); void loadBaselineOrIonNoArgCheck(Register callee, Register dest, ExecutionMode mode, Label *failure); diff --git a/js/src/jit/IonTypes.h b/js/src/jit/IonTypes.h index 0a7d9276ef7..4db7ec7cbbb 100644 --- a/js/src/jit/IonTypes.h +++ b/js/src/jit/IonTypes.h @@ -245,10 +245,7 @@ IsNullOrUndefined(MIRType type) // Make sure registers are not modified between an instruction and // its OsiPoint. -// -// Skip this check in rooting analysis builds, which poison unrooted -// pointers on the stack. -# if defined(JS_ION) && !defined(JSGC_ROOT_ANALYSIS) +# if defined(JS_ION) # define CHECK_OSIPOINT_REGISTERS 1 # endif #endif diff --git a/js/src/jit/LIR.h b/js/src/jit/LIR.h index c8add6063f5..992ff381d7c 100644 --- a/js/src/jit/LIR.h +++ b/js/src/jit/LIR.h @@ -987,9 +987,9 @@ class LSafepoint : public TempObject GeneralRegisterSet gcRegs_; #ifdef CHECK_OSIPOINT_REGISTERS - // Temp regs of the current instruction. This set is never written to the - // safepoint; it's only used by assertions during compilation. - RegisterSet tempRegs_; + // Clobbered regs of the current instruction. This set is never written to + // the safepoint; it's only used by assertions during compilation. + RegisterSet clobberedRegs_; #endif // Offset to a position in the safepoint stream, or @@ -1052,12 +1052,12 @@ class LSafepoint : public TempObject return liveRegs_; } #ifdef CHECK_OSIPOINT_REGISTERS - void addTempRegister(AnyRegister reg) { - tempRegs_.addUnchecked(reg); + void addClobberedRegister(AnyRegister reg) { + clobberedRegs_.addUnchecked(reg); assertInvariants(); } - const RegisterSet &tempRegs() const { - return tempRegs_; + const RegisterSet &clobberedRegs() const { + return clobberedRegs_; } #endif void addGcRegister(Register reg) { diff --git a/js/src/jit/LiveRangeAllocator.h b/js/src/jit/LiveRangeAllocator.h index 5cefc628547..47ab3dd495f 100644 --- a/js/src/jit/LiveRangeAllocator.h +++ b/js/src/jit/LiveRangeAllocator.h @@ -686,8 +686,16 @@ class LiveRangeAllocator : protected RegisterAllocator // Don't add output registers to the safepoint. CodePosition start = interval->start(); - if (interval->index() == 0 && !reg->isTemp()) + if (interval->index() == 0 && !reg->isTemp()) { +#ifdef CHECK_OSIPOINT_REGISTERS + // We don't add the output register to the safepoint, + // but it still might get added as one of the inputs. + // So eagerly add this reg to the safepoint clobbered registers. + if (LSafepoint *safepoint = reg->ins()->safepoint()) + safepoint->addClobberedRegister(a->toRegister()); +#endif start = start.next(); + } size_t i = findFirstNonCallSafepoint(start); for (; i < graph.numNonCallSafepoints(); i++) { @@ -707,7 +715,7 @@ class LiveRangeAllocator : protected RegisterAllocator #ifdef CHECK_OSIPOINT_REGISTERS if (reg->isTemp()) - safepoint->addTempRegister(a->toRegister()); + safepoint->addClobberedRegister(a->toRegister()); #endif } } diff --git a/js/src/jit/Safepoints.cpp b/js/src/jit/Safepoints.cpp index 0d9a16f701d..89b53ba1e30 100644 --- a/js/src/jit/Safepoints.cpp +++ b/js/src/jit/Safepoints.cpp @@ -43,12 +43,20 @@ SafepointWriter::writeOsiCallPointOffset(uint32_t osiCallPointOffset) static void WriteRegisterMask(CompactBufferWriter &stream, uint32_t bits) { - if (sizeof(PackedRegisterMask) == 8) + if (sizeof(PackedRegisterMask) == 1) stream.writeByte(bits); else stream.writeUnsigned(bits); } +static int32_t +ReadRegisterMask(CompactBufferReader &stream) +{ + if (sizeof(PackedRegisterMask) == 1) + return stream.readByte(); + return stream.readUnsigned(); +} + void SafepointWriter::writeGcRegs(LSafepoint *safepoint) { @@ -342,20 +350,20 @@ SafepointReader::SafepointReader(IonScript *script, const SafepointIndex *si) osiCallPointOffset_ = stream_.readUnsigned(); // gcSpills is a subset of allGprSpills. - allGprSpills_ = GeneralRegisterSet(stream_.readUnsigned()); + allGprSpills_ = GeneralRegisterSet(ReadRegisterMask(stream_)); if (allGprSpills_.empty()) { gcSpills_ = allGprSpills_; valueSpills_ = allGprSpills_; slotsOrElementsSpills_ = allGprSpills_; } else { - gcSpills_ = GeneralRegisterSet(stream_.readUnsigned()); - slotsOrElementsSpills_ = GeneralRegisterSet(stream_.readUnsigned()); + gcSpills_ = GeneralRegisterSet(ReadRegisterMask(stream_)); + slotsOrElementsSpills_ = GeneralRegisterSet(ReadRegisterMask(stream_)); #ifdef JS_PUNBOX64 - valueSpills_ = GeneralRegisterSet(stream_.readUnsigned()); + valueSpills_ = GeneralRegisterSet(ReadRegisterMask(stream_)); #endif } - allFloatSpills_ = FloatRegisterSet(stream_.readUnsigned()); + allFloatSpills_ = FloatRegisterSet(ReadRegisterMask(stream_)); advanceFromGcRegs(); } diff --git a/js/src/jit/Snapshots.cpp b/js/src/jit/Snapshots.cpp index dd9cebf32f2..0ce827dfadc 100644 --- a/js/src/jit/Snapshots.cpp +++ b/js/src/jit/Snapshots.cpp @@ -455,15 +455,12 @@ SnapshotReader::SnapshotReader(const uint8_t *snapshots, uint32_t offset, : reader_(snapshots + offset, snapshots + listSize), allocReader_(snapshots + listSize, snapshots + listSize + RVATableSize), allocTable_(snapshots + listSize), - allocCount_(0), - frameCount_(0), allocRead_(0) { if (!snapshots) return; IonSpew(IonSpew_Snapshots, "Creating snapshot reader"); readSnapshotHeader(); - nextFrame(); } static const uint32_t BAILOUT_KIND_SHIFT = 0; @@ -480,20 +477,7 @@ SnapshotReader::readSnapshotHeader() JS_ASSERT(frameCount_ > 0); bailoutKind_ = BailoutKind((bits >> BAILOUT_KIND_SHIFT) & BAILOUT_KIND_MASK); resumeAfter_ = !!(bits & (1 << BAILOUT_RESUME_SHIFT)); - framesRead_ = 0; - IonSpew(IonSpew_Snapshots, "Read snapshot header with frameCount %u, bailout kind %u (ra: %d)", - frameCount_, bailoutKind_, resumeAfter_); -} - -void -SnapshotReader::readFrameHeader() -{ - JS_ASSERT(moreFrames()); - JS_ASSERT(allocRead_ == allocCount_); - - pcOffset_ = reader_.readUnsigned(); - allocCount_ = reader_.readUnsigned(); #ifdef TRACK_SNAPSHOTS pcOpcode_ = reader_.readUnsigned(); mirOpcode_ = reader_.readUnsigned(); @@ -501,10 +485,9 @@ SnapshotReader::readFrameHeader() lirOpcode_ = reader_.readUnsigned(); lirId_ = reader_.readUnsigned(); #endif - IonSpew(IonSpew_Snapshots, "Read pc offset %u, nslots %u", pcOffset_, allocCount_); - framesRead_++; - allocRead_ = 0; + IonSpew(IonSpew_Snapshots, "Read snapshot header with frameCount %u, bailout kind %u (ra: %d)", + frameCount_, bailoutKind_, resumeAfter_); } #ifdef TRACK_SNAPSHOTS @@ -526,7 +509,6 @@ SnapshotReader::spewBailingFrom() const RValueAllocation SnapshotReader::readAllocation() { - JS_ASSERT(allocRead_ < allocCount_); IonSpew(IonSpew_Snapshots, "Reading slot %u", allocRead_); allocRead_++; @@ -544,12 +526,34 @@ SnapshotWriter::init() return allocMap_.init(32); } +RecoverReader::RecoverReader(SnapshotReader &snapshot) + : frameCount_(0), + framesRead_(0), + allocCount_(0) +{ + if (!snapshot.reader_.more()) + return; + frameCount_ = snapshot.frameCount_; + readFrame(snapshot); +} + +void +RecoverReader::readFrame(SnapshotReader &snapshot) +{ + JS_ASSERT(moreFrames()); + JS_ASSERT(snapshot.allocRead_ == allocCount_); + + pcOffset_ = snapshot.reader_.readUnsigned(); + allocCount_ = snapshot.reader_.readUnsigned(); + IonSpew(IonSpew_Snapshots, "Read pc offset %u, nslots %u", pcOffset_, allocCount_); + + framesRead_++; + snapshot.allocRead_ = 0; +} + SnapshotOffset SnapshotWriter::startSnapshot(uint32_t frameCount, BailoutKind kind, bool resumeAfter) { - nframes_ = frameCount; - framesWritten_ = 0; - lastStart_ = writer_.length(); IonSpew(IonSpew_Snapshots, "starting snapshot with frameCount %u, bailout kind %u", @@ -559,7 +563,7 @@ SnapshotWriter::startSnapshot(uint32_t frameCount, BailoutKind kind, bool resume JS_ASSERT(uint32_t(kind) < (1 << BAILOUT_KIND_BITS)); uint32_t bits = (uint32_t(kind) << BAILOUT_KIND_SHIFT) | - (frameCount << BAILOUT_FRAMECOUNT_SHIFT); + (frameCount << BAILOUT_FRAMECOUNT_SHIFT); if (resumeAfter) bits |= (1 << BAILOUT_RESUME_SHIFT); @@ -567,33 +571,10 @@ SnapshotWriter::startSnapshot(uint32_t frameCount, BailoutKind kind, bool resume return lastStart_; } -void -SnapshotWriter::startFrame(JSFunction *fun, JSScript *script, jsbytecode *pc, uint32_t exprStack) -{ - // Test if we honor the maximum of arguments at all times. - // This is a sanity check and not an algorithm limit. So check might be a bit too loose. - // +4 to account for scope chain, return value, this value and maybe arguments_object. - JS_ASSERT(CountArgSlots(script, fun) < SNAPSHOT_MAX_NARGS + 4); - - uint32_t implicit = StartArgSlot(script); - uint32_t formalArgs = CountArgSlots(script, fun); - - nallocs_ = formalArgs + script->nfixed() + exprStack; - allocWritten_ = 0; - - IonSpew(IonSpew_Snapshots, "Starting frame; implicit %u, formals %u, fixed %u, exprs %u", - implicit, formalArgs - implicit, script->nfixed(), exprStack); - - uint32_t pcoff = script->pcToOffset(pc); - IonSpew(IonSpew_Snapshots, "Writing pc offset %u, nslots %u", pcoff, nallocs_); - writer_.writeUnsigned(pcoff); - writer_.writeUnsigned(nallocs_); -} - #ifdef TRACK_SNAPSHOTS void -SnapshotWriter::trackFrame(uint32_t pcOpcode, uint32_t mirOpcode, uint32_t mirId, - uint32_t lirOpcode, uint32_t lirId) +SnapshotWriter::trackSnapshot(uint32_t pcOpcode, uint32_t mirOpcode, uint32_t mirId, + uint32_t lirOpcode, uint32_t lirId) { writer_.writeUnsigned(pcOpcode); writer_.writeUnsigned(mirOpcode); @@ -627,30 +608,71 @@ SnapshotWriter::add(const RValueAllocation &alloc) } allocWritten_++; - JS_ASSERT(allocWritten_ <= nallocs_); writer_.writeUnsigned(offset / ALLOCATION_TABLE_ALIGNMENT); return true; } -void -SnapshotWriter::endFrame() -{ - // Check that the last write succeeded. - JS_ASSERT(nallocs_ == allocWritten_); - nallocs_ = allocWritten_ = 0; - framesWritten_++; -} - void SnapshotWriter::endSnapshot() { - JS_ASSERT(nframes_ == framesWritten_); - // Place a sentinel for asserting on the other end. #ifdef DEBUG writer_.writeSigned(-1); #endif - + IonSpew(IonSpew_Snapshots, "ending snapshot total size: %u bytes (start %u)", uint32_t(writer_.length() - lastStart_), lastStart_); } + +RecoverWriter::RecoverWriter(SnapshotWriter &snapshot) + : snapshot_(snapshot) +{ +} + +SnapshotOffset +RecoverWriter::startRecover(uint32_t frameCount, BailoutKind kind, bool resumeAfter) +{ + MOZ_ASSERT(frameCount); + nframes_ = frameCount; + framesWritten_ = 0; + return snapshot_.startSnapshot(frameCount, kind, resumeAfter); +} + +void +RecoverWriter::startFrame(JSFunction *fun, JSScript *script, + jsbytecode *pc, uint32_t exprStack) +{ + // Test if we honor the maximum of arguments at all times. + // This is a sanity check and not an algorithm limit. So check might be a bit too loose. + // +4 to account for scope chain, return value, this value and maybe arguments_object. + JS_ASSERT(CountArgSlots(script, fun) < SNAPSHOT_MAX_NARGS + 4); + + uint32_t implicit = StartArgSlot(script); + uint32_t formalArgs = CountArgSlots(script, fun); + + nallocs_ = formalArgs + script->nfixed() + exprStack; + snapshot_.allocWritten_ = 0; + + IonSpew(IonSpew_Snapshots, "Starting frame; implicit %u, formals %u, fixed %u, exprs %u", + implicit, formalArgs - implicit, script->nfixed(), exprStack); + + uint32_t pcoff = script->pcToOffset(pc); + IonSpew(IonSpew_Snapshots, "Writing pc offset %u, nslots %u", pcoff, nallocs_); + snapshot_.writer_.writeUnsigned(pcoff); + snapshot_.writer_.writeUnsigned(nallocs_); +} + +void +RecoverWriter::endFrame() +{ + MOZ_ASSERT(snapshot_.allocWritten_ == nallocs_); + nallocs_ = snapshot_.allocWritten_ = 0; + framesWritten_++; +} + +void +RecoverWriter::endRecover() +{ + snapshot_.endSnapshot(); + JS_ASSERT(nframes_ == framesWritten_); +} diff --git a/js/src/jit/Snapshots.h b/js/src/jit/Snapshots.h index 6cbd541af51..c4d652f27ec 100644 --- a/js/src/jit/Snapshots.h +++ b/js/src/jit/Snapshots.h @@ -302,10 +302,13 @@ class RValueAllocation }; }; +class RecoverWriter; + // Collects snapshots in a contiguous buffer, which is copied into IonScript // memory after code generation. class SnapshotWriter { + friend class RecoverWriter; CompactBufferWriter writer_; CompactBufferWriter allocWriter_; @@ -315,24 +318,20 @@ class SnapshotWriter typedef HashMap RValueAllocMap; RValueAllocMap allocMap_; - // These are only used to assert sanity. - uint32_t nallocs_; + // This is only used to assert sanity. uint32_t allocWritten_; - uint32_t nframes_; - uint32_t framesWritten_; + + // Used to report size of the snapshot in the spew messages. SnapshotOffset lastStart_; public: bool init(); SnapshotOffset startSnapshot(uint32_t frameCount, BailoutKind kind, bool resumeAfter); - void startFrame(JSFunction *fun, JSScript *script, jsbytecode *pc, uint32_t exprStack); #ifdef TRACK_SNAPSHOTS - void trackFrame(uint32_t pcOpcode, uint32_t mirOpcode, uint32_t mirId, - uint32_t lirOpcode, uint32_t lirId); + void trackSnapshot(uint32_t pcOpcode, uint32_t mirOpcode, uint32_t mirId, + uint32_t lirOpcode, uint32_t lirId); #endif - void endFrame(); - bool add(const RValueAllocation &slot); void endSnapshot(); @@ -356,21 +355,42 @@ class SnapshotWriter } }; +class RecoverWriter +{ + SnapshotWriter &snapshot_; + + uint32_t nallocs_; + + uint32_t nframes_; + uint32_t framesWritten_; + + public: + RecoverWriter(SnapshotWriter &snapshot); + + SnapshotOffset startRecover(uint32_t frameCount, BailoutKind kind, bool resumeAfter); + + void startFrame(JSFunction *fun, JSScript *script, jsbytecode *pc, uint32_t exprStack); + void endFrame(); + + void endRecover(); +}; + +class RecoverReader; + // A snapshot reader reads the entries out of the compressed snapshot buffer in // a script. These entries describe the equivalent interpreter frames at a given // position in JIT code. Each entry is an Ion's value allocations, used to // recover the corresponding Value from an Ion frame. class SnapshotReader { + friend class RecoverReader; + CompactBufferReader reader_; CompactBufferReader allocReader_; const uint8_t* allocTable_; - uint32_t pcOffset_; // Offset from script->code. - uint32_t allocCount_; // Number of slots. uint32_t frameCount_; BailoutKind bailoutKind_; - uint32_t framesRead_; // Number of frame headers that have been read. uint32_t allocRead_; // Number of slots that have been read. bool resumeAfter_; @@ -394,34 +414,49 @@ class SnapshotReader SnapshotReader(const uint8_t *snapshots, uint32_t offset, uint32_t RVATableSize, uint32_t listSize); - uint32_t pcOffset() const { - return pcOffset_; - } - uint32_t allocations() const { - return allocCount_; - } + RValueAllocation readAllocation(); + BailoutKind bailoutKind() const { return bailoutKind_; } bool resumeAfter() const { - if (moreFrames()) - return false; return resumeAfter_; } +}; + +class RecoverReader +{ + uint32_t frameCount_; + uint32_t framesRead_; // Number of frame headers that have been read. + uint32_t pcOffset_; // Offset from script->code. + uint32_t allocCount_; // Number of slots. + + private: + void readFrame(SnapshotReader &snapshot); + + public: + RecoverReader(SnapshotReader &snapshot); + bool moreFrames() const { return framesRead_ < frameCount_; } - void nextFrame() { - readFrameHeader(); - } - RValueAllocation readAllocation(); - - bool moreAllocations() const { - return allocRead_ < allocCount_; + void nextFrame(SnapshotReader &snapshot) { + readFrame(snapshot); } uint32_t frameCount() const { return frameCount_; } + + uint32_t pcOffset() const { + return pcOffset_; + } + + uint32_t allocations() const { + return allocCount_; + } + bool moreAllocations(const SnapshotReader &snapshot) const { + return snapshot.allocRead_ < allocCount_; + } }; } diff --git a/js/src/jit/arm/Trampoline-arm.cpp b/js/src/jit/arm/Trampoline-arm.cpp index cced3aaf382..8aeb5f9d29c 100644 --- a/js/src/jit/arm/Trampoline-arm.cpp +++ b/js/src/jit/arm/Trampoline-arm.cpp @@ -33,13 +33,13 @@ static const FloatRegisterSet NonVolatileFloatRegs = (1 << FloatRegisters::d15)); static void -GenerateReturn(MacroAssembler &masm, int returnCode) +GenerateReturn(MacroAssembler &masm, int returnCode, SPSProfiler *prof) { // Restore non-volatile floating point registers masm.transferMultipleByRuns(NonVolatileFloatRegs, IsLoad, StackPointer, IA); - // Get rid of the bogus r0 push. - masm.as_add(sp, sp, Imm8(4)); + // Unwind the sps mark. + masm.spsUnmarkJit(prof, r8); // Set up return value masm.ma_mov(Imm32(returnCode), r0); @@ -71,7 +71,7 @@ struct EnterJITStack double d14; double d15; - void *r0; // alignment. + size_t hasSPSMark; // non-volatile registers. void *r4; @@ -119,19 +119,24 @@ JitRuntime::generateEnterJIT(JSContext *cx, EnterJitType type) // rather than the JIT'd code, because they are scanned by the conservative // scanner. masm.startDataTransferM(IsStore, sp, DB, WriteBack); - masm.transferReg(r0); // [sp,0] - masm.transferReg(r4); // [sp,4] - masm.transferReg(r5); // [sp,8] - masm.transferReg(r6); // [sp,12] - masm.transferReg(r7); // [sp,16] - masm.transferReg(r8); // [sp,20] - masm.transferReg(r9); // [sp,24] - masm.transferReg(r10); // [sp,28] - masm.transferReg(r11); // [sp,32] + masm.transferReg(r4); // [sp,0] + masm.transferReg(r5); // [sp,4] + masm.transferReg(r6); // [sp,8] + masm.transferReg(r7); // [sp,12] + masm.transferReg(r8); // [sp,16] + masm.transferReg(r9); // [sp,20] + masm.transferReg(r10); // [sp,24] + masm.transferReg(r11); // [sp,28] // The abi does not expect r12 (ip) to be preserved - masm.transferReg(lr); // [sp,36] - // The 5th argument is located at [sp, 40] + masm.transferReg(lr); // [sp,32] + // The 5th argument is located at [sp, 36] masm.finishDataTransfer(); + + // Push the EnterJIT sps mark. "Frame pointer" = start of saved core regs. + masm.movePtr(sp, r8); + masm.spsMarkJit(&cx->runtime()->spsProfiler, r8, r9); + + // Push the float registers. masm.transferMultipleByRuns(NonVolatileFloatRegs, IsStore, sp, DB); // Save stack pointer into r8 @@ -324,7 +329,7 @@ JitRuntime::generateEnterJIT(JSContext *cx, EnterJitType type) // JSReturnReg_Data, EDtrAddr(r5, EDtrOffImm(0))); // Restore non-volatile registers and return. - GenerateReturn(masm, true); + GenerateReturn(masm, true, &cx->runtime()->spsProfiler); Linker linker(masm); JitCode *code = linker.newCode(cx, JSC::OTHER_CODE); diff --git a/js/src/jit/shared/CodeGenerator-shared.cpp b/js/src/jit/shared/CodeGenerator-shared.cpp index 3ed8021e8ba..c84dd1ab32b 100644 --- a/js/src/jit/shared/CodeGenerator-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-shared.cpp @@ -41,6 +41,8 @@ CodeGeneratorShared::CodeGeneratorShared(MIRGenerator *gen, LIRGraph *graph, Mac gen(gen), graph(*graph), current(nullptr), + snapshots_(), + recovers_(snapshots_), deoptTable_(nullptr), #ifdef DEBUG pushedArgs_(0), @@ -247,8 +249,28 @@ CodeGeneratorShared::encode(LSnapshot *snapshot) JS_ASSERT(mode != MResumePoint::Outer); bool resumeAfter = (mode == MResumePoint::ResumeAfter); - SnapshotOffset offset = snapshots_.startSnapshot(frameCount, snapshot->bailoutKind(), - resumeAfter); + SnapshotOffset offset = recovers_.startRecover(frameCount, snapshot->bailoutKind(), + resumeAfter); + +#ifdef TRACK_SNAPSHOTS + uint32_t pcOpcode = 0; + uint32_t lirOpcode = 0; + uint32_t lirId = 0; + uint32_t mirOpcode = 0; + uint32_t mirId = 0; + + if (LInstruction *ins = instruction()) { + lirOpcode = ins->op(); + lirId = ins->id(); + if (ins->mirRaw()) { + mirOpcode = ins->mirRaw()->op(); + mirId = ins->mirRaw()->id(); + if (ins->mirRaw()->trackedPc()) + pcOpcode = *ins->mirRaw()->trackedPc(); + } + } + snapshots_.trackSnapshot(pcOpcode, mirOpcode, mirId, lirOpcode, lirId); +#endif FlattenedMResumePointIter mirOperandIter(snapshot->mir()); if (!mirOperandIter.init()) @@ -265,7 +287,7 @@ CodeGeneratorShared::encode(LSnapshot *snapshot) JSScript *script = block->info().script(); jsbytecode *pc = mir->pc(); uint32_t exprStack = mir->stackDepth() - block->info().ninvoke(); - snapshots_.startFrame(fun, script, pc, exprStack); + recovers_.startFrame(fun, script, pc, exprStack); // Ensure that all snapshot which are encoded can safely be used for // bailouts. @@ -305,35 +327,12 @@ CodeGeneratorShared::encode(LSnapshot *snapshot) } #endif -#ifdef TRACK_SNAPSHOTS - LInstruction *ins = instruction(); - - uint32_t pcOpcode = 0; - uint32_t lirOpcode = 0; - uint32_t lirId = 0; - uint32_t mirOpcode = 0; - uint32_t mirId = 0; - - if (ins) { - lirOpcode = ins->op(); - lirId = ins->id(); - if (ins->mirRaw()) { - mirOpcode = ins->mirRaw()->op(); - mirId = ins->mirRaw()->id(); - if (ins->mirRaw()->trackedPc()) - pcOpcode = *ins->mirRaw()->trackedPc(); - } - } - snapshots_.trackFrame(pcOpcode, mirOpcode, mirId, lirOpcode, lirId); -#endif - if (!encodeAllocations(snapshot, mir, &startIndex)) return false; - snapshots_.endFrame(); + recovers_.endFrame(); } - snapshots_.endSnapshot(); - + recovers_.endRecover(); snapshot->setSnapshotOffset(offset); return !snapshots_.oom(); @@ -560,11 +559,13 @@ CodeGeneratorShared::verifyOsiPointRegs(LSafepoint *safepoint) // before the return address. masm.branch32(Assembler::NotEqual, checkRegs, Imm32(1), &failure); - // Ignore temp registers. Some instructions (like LValueToInt32) modify + // Ignore clobbered registers. Some instructions (like LValueToInt32) modify // temps after calling into the VM. This is fine because no other - // instructions (including this OsiPoint) will depend on them. + // instructions (including this OsiPoint) will depend on them. Also + // backtracking can also use the same register for an input and an output. + // These are marked as clobbered and shouldn't get checked. RegisterSet liveRegs = safepoint->liveRegs(); - liveRegs = RegisterSet::Intersect(liveRegs, RegisterSet::Not(safepoint->tempRegs())); + liveRegs = RegisterSet::Intersect(liveRegs, RegisterSet::Not(safepoint->clobberedRegs())); VerifyOp op(masm, &failure); HandleRegisterDump(op, masm, liveRegs, scratch, allRegs.getAny()); diff --git a/js/src/jit/shared/CodeGenerator-shared.h b/js/src/jit/shared/CodeGenerator-shared.h index 55a95563be6..ea3807d9967 100644 --- a/js/src/jit/shared/CodeGenerator-shared.h +++ b/js/src/jit/shared/CodeGenerator-shared.h @@ -61,6 +61,7 @@ class CodeGeneratorShared : public LInstructionVisitor LIRGraph &graph; LBlock *current; SnapshotWriter snapshots_; + RecoverWriter recovers_; JitCode *deoptTable_; #ifdef DEBUG uint32_t pushedArgs_; diff --git a/js/src/jit/x64/MacroAssembler-x64.h b/js/src/jit/x64/MacroAssembler-x64.h index fd4610e2b44..fa273cbdc0c 100644 --- a/js/src/jit/x64/MacroAssembler-x64.h +++ b/js/src/jit/x64/MacroAssembler-x64.h @@ -78,6 +78,8 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared using MacroAssemblerX86Shared::Pop; using MacroAssemblerX86Shared::callWithExitFrame; using MacroAssemblerX86Shared::branch32; + using MacroAssemblerX86Shared::load32; + using MacroAssemblerX86Shared::store32; MacroAssemblerX64() : inCall_(false), @@ -662,7 +664,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared movq(Operand(address), dest); } else { mov(ImmPtr(address.addr), ScratchReg); - movq(Operand(ScratchReg, 0x0), dest); + loadPtr(Address(ScratchReg, 0x0), dest); } } void loadPtr(const Address &address, Register dest) { @@ -678,6 +680,14 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared loadPtr(src, dest); shlq(Imm32(1), dest); } + void load32(const AbsoluteAddress &address, Register dest) { + if (JSC::X86Assembler::isAddressImmediate(address.addr)) { + movl(Operand(address), dest); + } else { + mov(ImmPtr(address.addr), ScratchReg); + load32(Address(ScratchReg, 0x0), dest); + } + } void storePtr(ImmWord imm, const Address &address) { if ((intptr_t)imm.value <= INT32_MAX && (intptr_t)imm.value >= INT32_MIN) { movq(Imm32((int32_t)imm.value), Operand(address)); @@ -704,7 +714,15 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared movq(src, Operand(address)); } else { mov(ImmPtr(address.addr), ScratchReg); - movq(src, Operand(ScratchReg, 0x0)); + storePtr(src, Address(ScratchReg, 0x0)); + } + } + void store32(const Register &src, const AbsoluteAddress &address) { + if (JSC::X86Assembler::isAddressImmediate(address.addr)) { + movl(src, Operand(address)); + } else { + mov(ImmPtr(address.addr), ScratchReg); + store32(src, Address(ScratchReg, 0x0)); } } void rshiftPtr(Imm32 imm, Register dest) { diff --git a/js/src/jit/x64/Trampoline-x64.cpp b/js/src/jit/x64/Trampoline-x64.cpp index 819b39956cb..72f459260fe 100644 --- a/js/src/jit/x64/Trampoline-x64.cpp +++ b/js/src/jit/x64/Trampoline-x64.cpp @@ -81,6 +81,9 @@ JitRuntime::generateEnterJIT(JSContext *cx, EnterJitType type) masm.movdqa(xmm15, Operand(rsp, 16 * 9)); #endif + // Push the EnterJIT sps mark. + masm.spsMarkJit(&cx->runtime()->spsProfiler, rbp, rbx); + // Save arguments passed in registers needed after function call. masm.push(result); @@ -263,6 +266,9 @@ JitRuntime::generateEnterJIT(JSContext *cx, EnterJitType type) masm.pop(r12); // vp masm.storeValue(JSReturnOperand, Operand(r12, 0)); + // Unwind the sps mark. + masm.spsUnmarkJit(&cx->runtime()->spsProfiler, rbx); + // Restore non-volatile registers. #if defined(_WIN64) masm.movdqa(Operand(rsp, 16 * 0), xmm6); diff --git a/js/src/jit/x86/MacroAssembler-x86.h b/js/src/jit/x86/MacroAssembler-x86.h index ac41130baa4..8d81b9f57a2 100644 --- a/js/src/jit/x86/MacroAssembler-x86.h +++ b/js/src/jit/x86/MacroAssembler-x86.h @@ -69,6 +69,8 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared using MacroAssemblerX86Shared::Pop; using MacroAssemblerX86Shared::callWithExitFrame; using MacroAssemblerX86Shared::branch32; + using MacroAssemblerX86Shared::load32; + using MacroAssemblerX86Shared::store32; MacroAssemblerX86() : inCall_(false), @@ -662,6 +664,9 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared void loadPrivate(const Address &src, Register dest) { movl(payloadOf(src), dest); } + void load32(const AbsoluteAddress &address, Register dest) { + movl(Operand(address), dest); + } void storePtr(ImmWord imm, const Address &address) { movl(Imm32(imm.value), Operand(address)); } @@ -680,6 +685,9 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared void storePtr(Register src, const AbsoluteAddress &address) { movl(src, Operand(address)); } + void store32(Register src, const AbsoluteAddress &address) { + movl(src, Operand(address)); + } void setStackArg(const Register ®, uint32_t arg) { movl(reg, Operand(esp, arg * sizeof(intptr_t))); diff --git a/js/src/jit/x86/Trampoline-x86.cpp b/js/src/jit/x86/Trampoline-x86.cpp index 242321b22d2..79f0e60d92d 100644 --- a/js/src/jit/x86/Trampoline-x86.cpp +++ b/js/src/jit/x86/Trampoline-x86.cpp @@ -61,6 +61,12 @@ JitRuntime::generateEnterJIT(JSContext *cx, EnterJitType type) masm.push(ebx); masm.push(esi); masm.push(edi); + + // Push the EnterJIT sps mark. + masm.spsMarkJit(&cx->runtime()->spsProfiler, ebp, ebx); + + // Keep track of the stack which has to be unwound after returning from the + // compiled function. masm.movl(esp, esi); // eax <- 8*argc, eax is now the offset betwen argv and the last @@ -77,7 +83,7 @@ JitRuntime::generateEnterJIT(JSContext *cx, EnterJitType type) // +4 for pushing the return address masm.movl(esp, ecx); masm.subl(eax, ecx); - masm.subl(Imm32(12), ecx); + masm.subl(Imm32(4 * 3), ecx); // ecx = ecx & 15, holds alignment. masm.andl(Imm32(15), ecx); @@ -253,18 +259,22 @@ JitRuntime::generateEnterJIT(JSContext *cx, EnterJitType type) // |ebp| could have been clobbered by the inner function. // Grab the address for the Value result from the argument stack. - // +18 ... arguments ... - // +14 - // +10 ebp <- original %ebp pointing here. - // +8 ebx - // +4 esi - // +0 edi - masm.loadPtr(Address(esp, ARG_RESULT + 3 * sizeof(void *)), eax); + // +24 ... arguments ... + // +20 + // +16 ebp <- original %ebp pointing here. + // +12 ebx + // +8 esi + // +4 edi + // +0 hasSPSFrame + masm.loadPtr(Address(esp, ARG_RESULT + 4 * sizeof(void *)), eax); masm.storeValue(JSReturnOperand, Operand(eax, 0)); /************************************************************** Return stack and registers to correct state **************************************************************/ + // Unwind the sps mark. + masm.spsUnmarkJit(&cx->runtime()->spsProfiler, ebx); + // Restore non-volatile registers masm.pop(edi); masm.pop(esi); diff --git a/js/src/jsapi-tests/testConservativeGC.cpp b/js/src/jsapi-tests/testConservativeGC.cpp index 16c4456804f..e51496c7426 100644 --- a/js/src/jsapi-tests/testConservativeGC.cpp +++ b/js/src/jsapi-tests/testConservativeGC.cpp @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#if !defined(JSGC_ROOT_ANALYSIS) && !defined(JSGC_USE_EXACT_ROOTING) +#if !defined(JSGC_USE_EXACT_ROOTING) #include "jsobj.h" @@ -85,4 +85,4 @@ BEGIN_TEST(testDerivedValues) } END_TEST(testDerivedValues) -#endif /* !defined(JSGC_ROOT_ANALYSIS) && !defined(JSGC_USE_EXACT_ROOTING) */ +#endif /* !defined(JSGC_USE_EXACT_ROOTING) */ diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 334b5734e8a..0f85c9f8afb 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -142,12 +142,11 @@ class AutoValueArray : public AutoGCRooter { const size_t length_; Value elements_[N]; - js::SkipRoot skip_; public: AutoValueArray(JSContext *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, VALARRAY), length_(N), skip_(cx, elements_, N) + : AutoGCRooter(cx, VALARRAY), length_(N) { /* Always initialize in case we GC before assignment. */ mozilla::PodArrayZero(elements_); @@ -176,20 +175,17 @@ class AutoVectorRooter : protected AutoGCRooter typedef js::Vector VectorImpl; VectorImpl vector; - /* Prevent overwriting of inline elements in vector. */ - js::SkipRoot vectorRoot; - public: explicit AutoVectorRooter(JSContext *cx, ptrdiff_t tag MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, tag), vector(cx), vectorRoot(cx, &vector) + : AutoGCRooter(cx, tag), vector(cx) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } explicit AutoVectorRooter(js::ContextFriendFields *cx, ptrdiff_t tag MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, tag), vector(cx), vectorRoot(cx, &vector) + : AutoGCRooter(cx, tag), vector(cx) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } @@ -1039,10 +1035,6 @@ MOZ_ALWAYS_INLINE bool ToNumber(JSContext *cx, HandleValue v, double *out) { AssertArgumentsAreSane(cx, v); - { - js::SkipRoot root(cx, &v); - js::MaybeCheckStackRoots(cx); - } if (v.isNumber()) { *out = v.toNumber(); @@ -1117,7 +1109,6 @@ MOZ_ALWAYS_INLINE bool ToUint16(JSContext *cx, JS::HandleValue v, uint16_t *out) { AssertArgumentsAreSane(cx, v); - js::MaybeCheckStackRoots(cx); if (v.isInt32()) { *out = uint16_t(v.toInt32()); @@ -1130,7 +1121,6 @@ MOZ_ALWAYS_INLINE bool ToInt32(JSContext *cx, JS::HandleValue v, int32_t *out) { AssertArgumentsAreSane(cx, v); - js::MaybeCheckStackRoots(cx); if (v.isInt32()) { *out = v.toInt32(); @@ -1143,7 +1133,6 @@ MOZ_ALWAYS_INLINE bool ToUint32(JSContext *cx, JS::HandleValue v, uint32_t *out) { AssertArgumentsAreSane(cx, v); - js::MaybeCheckStackRoots(cx); if (v.isInt32()) { *out = uint32_t(v.toInt32()); @@ -1156,13 +1145,11 @@ MOZ_ALWAYS_INLINE bool ToInt64(JSContext *cx, JS::HandleValue v, int64_t *out) { AssertArgumentsAreSane(cx, v); - js::MaybeCheckStackRoots(cx); if (v.isInt32()) { *out = int64_t(v.toInt32()); return true; } - return js::ToInt64Slow(cx, v, out); } @@ -1170,14 +1157,12 @@ MOZ_ALWAYS_INLINE bool ToUint64(JSContext *cx, JS::HandleValue v, uint64_t *out) { AssertArgumentsAreSane(cx, v); - js::MaybeCheckStackRoots(cx); if (v.isInt32()) { /* Account for sign extension of negatives into the longer 64bit space. */ *out = uint64_t(int64_t(v.toInt32())); return true; } - return js::ToUint64Slow(cx, v, out); } diff --git a/js/src/jsatom.cpp b/js/src/jsatom.cpp index c9f76870c5a..da09f23cad1 100644 --- a/js/src/jsatom.cpp +++ b/js/src/jsatom.cpp @@ -325,7 +325,6 @@ AtomizeAndtake(ExclusiveContext *cx, jschar *tbchars, size_t length, InternBehav */ AtomSet& atoms = cx->atoms(); AtomSet::AddPtr p = atoms.lookupForAdd(lookup); - SkipRoot skipHash(cx, &p); /* Prevent the hash from being poisoned. */ if (p) { JSAtom *atom = p->asPtr(); p->setTagged(bool(ib)); @@ -377,7 +376,6 @@ AtomizeAndCopyChars(ExclusiveContext *cx, const jschar *tbchars, size_t length, AtomSet& atoms = cx->atoms(); AtomSet::AddPtr p = atoms.lookupForAdd(lookup); - SkipRoot skipHash(cx, &p); /* Prevent the hash from being poisoned. */ if (p) { JSAtom *atom = p->asPtr(); p->setTagged(bool(ib)); diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 2eef7b11763..241f2bf7df2 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -232,7 +232,7 @@ js::DestroyContext(JSContext *cx, DestroyContextMode mode) MOZ_CRASH(); #endif -#if (defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)) && defined(DEBUG) +#if defined(JSGC_USE_EXACT_ROOTING) && defined(DEBUG) for (int i = 0; i < THING_ROOT_LIMIT; ++i) JS_ASSERT(cx->thingGCRooters[i] == nullptr); #endif diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 2c96173b11d..f5322b3fe58 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -393,12 +393,6 @@ class ExclusiveContext : public ThreadSafeContext void addPendingOverRecursed(); }; -inline void -MaybeCheckStackRoots(ExclusiveContext *cx) -{ - MaybeCheckStackRoots(cx->maybeJSContext()); -} - } /* namespace js */ struct JSContext : public js::ExclusiveContext, @@ -934,7 +928,7 @@ class AutoArrayRooter : private AutoGCRooter public: AutoArrayRooter(JSContext *cx, size_t len, Value *vec MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, len), array(vec), skip(cx, array, len) + : AutoGCRooter(cx, len), array(vec) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; JS_ASSERT(tag_ >= 0); @@ -980,7 +974,6 @@ class AutoArrayRooter : private AutoGCRooter private: Value *array; - js::SkipRoot skip; MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index f6fb42d0d38..4618377899e 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -39,12 +39,9 @@ JS_STATIC_ASSERT(offsetof(JSRuntime, mainThread) == PerThreadDataFriendFields::PerThreadDataFriendFields() { PodArrayZero(nativeStackLimit); -#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING) +#if defined(JSGC_USE_EXACT_ROOTING) PodArrayZero(thingGCRooters); #endif -#if defined(DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE) - skipGCRooters = nullptr; -#endif } JS_FRIEND_API(void) diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 685242152b4..c6df08f8083 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -1589,9 +1589,6 @@ FunctionConstructor(JSContext *cx, unsigned argc, Value *vp, GeneratorKind gener const jschar *chars = linear->chars(); size_t length = linear->length(); - /* Protect inlined chars from root analysis poisoning. */ - SkipRoot skip(cx, &chars); - /* * NB: (new Function) is not lexically closed by its caller, it's just an * anonymous function in the top-level scope that its constructor inhabits. diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index a2fb50f5c46..71969cfcf22 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -667,8 +667,7 @@ ChunkPool::get(JSRuntime *rt) chunk = Chunk::allocate(rt); if (!chunk) return nullptr; - JS_ASSERT(chunk->info.numArenasFreeCommitted == ArenasPerChunk); - rt->gcNumArenasFreeCommitted += ArenasPerChunk; + JS_ASSERT(chunk->info.numArenasFreeCommitted == 0); } JS_ASSERT(chunk->unused()); JS_ASSERT(!rt->gcChunkSet.has(chunk)); @@ -747,21 +746,6 @@ ChunkPool::expireAndFree(JSRuntime *rt, bool releaseAll) Chunk::allocate(JSRuntime *rt) { Chunk *chunk = AllocChunk(rt); - -#ifdef JSGC_ROOT_ANALYSIS - // Our poison pointers are not guaranteed to be invalid on 64-bit - // architectures, and often are valid. We can't just reserve the full - // poison range, because it might already have been taken up by something - // else (shared library, previous allocation). So we'll just loop and - // discard poison pointers until we get something valid. - // - // This leaks all of these poisoned pointers. It would be better if they - // were marked as uncommitted, but it's a little complicated to avoid - // clobbering pre-existing unrelated mappings. - while (IsPoisonedPtr(chunk)) - chunk = AllocChunk(rt); -#endif - if (!chunk) return nullptr; chunk->init(rt); @@ -805,25 +789,16 @@ Chunk::init(JSRuntime *rt) */ bitmap.clear(); - /* Initialize the arena tracking bitmap. */ - decommittedArenas.clear(false); + /* + * Decommit the arenas. We do this after poisoning so that if the OS does + * not have to recycle the pages, we still get the benefit of poisoning. + */ + decommitAllArenas(rt); /* Initialize the chunk info. */ - info.freeArenasHead = &arenas[0].aheader; - info.lastDecommittedArenaOffset = 0; - info.numArenasFree = ArenasPerChunk; - info.numArenasFreeCommitted = ArenasPerChunk; info.age = 0; info.trailer.runtime = rt; - /* Initialize the arena header state. */ - for (unsigned i = 0; i < ArenasPerChunk; i++) { - arenas[i].aheader.setAsNotAllocated(); - arenas[i].aheader.next = (i + 1 < ArenasPerChunk) - ? &arenas[i + 1].aheader - : nullptr; - } - /* The rest of info fields are initialized in PickChunk. */ } @@ -999,6 +974,8 @@ Chunk::releaseArena(ArenaHeader *aheader) } else { rt->gcChunkSet.remove(this); removeFromAvailableList(); + JS_ASSERT(info.numArenasFree == ArenasPerChunk); + decommitAllArenas(rt); rt->gcChunkPool.put(this); } } @@ -2622,12 +2599,11 @@ GCHelperThread::threadLoop() /* OOM stops the background allocation. */ if (!chunk) { #if JS_TRACE_LOGGING - logger->log(TraceLogging::GC_ALLOCATING_STOP); + logger->log(TraceLogging::GC_ALLOCATING_STOP); #endif break; } - JS_ASSERT(chunk->info.numArenasFreeCommitted == ArenasPerChunk); - rt->gcNumArenasFreeCommitted += ArenasPerChunk; + JS_ASSERT(chunk->info.numArenasFreeCommitted == 0); rt->gcChunkPool.put(chunk); } while (state == ALLOCATING && rt->gcChunkPool.wantBackgroundAllocation(rt)); if (state == ALLOCATING) @@ -4361,6 +4337,9 @@ AutoTraceSession::AutoTraceSession(JSRuntime *rt, js::HeapState heapState) JS_ASSERT(!rt->noGCOrAllocationCheck); JS_ASSERT(!rt->isHeapBusy()); JS_ASSERT(heapState != Idle); +#ifdef JSGC_GENERATIONAL + JS_ASSERT_IF(heapState == MajorCollecting, rt->gcNursery.isEmpty()); +#endif // Threads with an exclusive context can hit refillFreeList while holding // the exclusive access lock. To avoid deadlocking when we try to acquire @@ -4822,9 +4801,6 @@ static MOZ_NEVER_INLINE bool GCCycle(JSRuntime *rt, bool incremental, int64_t budget, JSGCInvocationKind gckind, JS::gcreason::Reason reason) { - /* If we attempt to invoke the GC while we are running in the GC, assert. */ - JS_ASSERT(!rt->isHeapBusy()); - AutoGCSession gcsession(rt); /* @@ -4923,6 +4899,9 @@ Collect(JSRuntime *rt, bool incremental, int64_t budget, JS_AbortIfWrongThread(rt); + /* If we attempt to invoke the GC while we are running in the GC, assert. */ + JS_ASSERT(!rt->isHeapBusy()); + if (rt->mainThread.suppressGC) return; @@ -4932,10 +4911,6 @@ Collect(JSRuntime *rt, bool incremental, int64_t budget, TraceLogging::GC_STOP); #endif - ContextIter cx(rt); - if (!cx.done()) - MaybeCheckStackRoots(cx); - #ifdef JS_GC_ZEAL if (rt->gcDeterministicOnly && !IsDeterministicGCReason(reason)) return; @@ -4946,14 +4921,6 @@ Collect(JSRuntime *rt, bool incremental, int64_t budget, AutoStopVerifyingBarriers av(rt, reason == JS::gcreason::SHUTDOWN_CC || reason == JS::gcreason::DESTROY_RUNTIME); - MinorGC(rt, reason); - - /* - * Marking can trigger many incidental post barriers, some of them for - * objects which are not going to be live after the GC. - */ - AutoDisableStoreBuffer adsb(rt); - RecordNativeStackTopForGC(rt); int zoneCount = 0; @@ -4977,11 +4944,18 @@ Collect(JSRuntime *rt, bool incremental, int64_t budget, rt->gcShouldCleanUpEverything = ShouldCleanUpEverything(rt, reason, gckind); - gcstats::AutoGCSlice agc(rt->gcStats, collectedCount, zoneCount, compartmentCount, reason); - bool repeat = false; - do { + MinorGC(rt, reason); + + /* + * Marking can trigger many incidental post barriers, some of them for + * objects which are not going to be live after the GC. + */ + AutoDisableStoreBuffer adsb(rt); + + gcstats::AutoGCSlice agc(rt->gcStats, collectedCount, zoneCount, compartmentCount, reason); + /* * Let the API user decide to defer a GC if it wants to (unless this * is the last context). Invoke the callback regardless. @@ -5100,6 +5074,7 @@ js::MinorGC(JSRuntime *rt, JS::gcreason::Reason reason) TraceLogging::MINOR_GC_STOP); #endif rt->gcNursery.collect(rt, reason, nullptr); + JS_ASSERT_IF(!rt->mainThread.suppressGC, rt->gcNursery.isEmpty()); #endif } @@ -5115,11 +5090,13 @@ js::MinorGC(JSContext *cx, JS::gcreason::Reason reason) TraceLogging::MINOR_GC_STOP); #endif Nursery::TypeObjectList pretenureTypes; - cx->runtime()->gcNursery.collect(cx->runtime(), reason, &pretenureTypes); + JSRuntime *rt = cx->runtime(); + rt->gcNursery.collect(cx->runtime(), reason, &pretenureTypes); for (size_t i = 0; i < pretenureTypes.length(); i++) { if (pretenureTypes[i]->canPreTenure()) pretenureTypes[i]->setShouldPreTenure(cx); } + JS_ASSERT_IF(!rt->mainThread.suppressGC, rt->gcNursery.isEmpty()); #endif } diff --git a/js/src/jsgcinlines.h b/js/src/jsgcinlines.h index 90053f95357..148f6551a51 100644 --- a/js/src/jsgcinlines.h +++ b/js/src/jsgcinlines.h @@ -437,8 +437,6 @@ CheckAllocatorState(ThreadSafeContext *cx, AllocKind kind) // handle that here. Just check in case we need to collect instead. js::gc::GCIfNeeded(ncx); } - - MaybeCheckStackRoots(ncx); } return true; diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index d6b7a5fd947..1efe71d34e0 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -3384,17 +3384,7 @@ CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun) size_t numBytes = sizeof(TypeNewScript) + (initializerList.length() * sizeof(TypeNewScript::Initializer)); - TypeNewScript *newScript; -#ifdef JSGC_ROOT_ANALYSIS - // calloc can legitimately return a pointer that appears to be poisoned. - void *p; - do { - p = cx->calloc_(numBytes); - } while (IsPoisonedPtr(p)); - newScript = (TypeNewScript *) p; -#else - newScript = (TypeNewScript *) cx->calloc_(numBytes); -#endif + TypeNewScript *newScript = (TypeNewScript *) cx->calloc_(numBytes); if (!newScript) return; diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index dd0b710a394..da22734bf47 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -1562,25 +1562,6 @@ js::NonObjectToNumberSlow(ThreadSafeContext *cx, Value v, double *out) bool js::ToNumberSlow(ExclusiveContext *cx, Value v, double *out) { -#ifdef DEBUG - /* - * MSVC bizarrely miscompiles this, complaining about the first brace below - * being unmatched (!). The error message points at both this opening brace - * and at the corresponding SkipRoot constructor. The error seems to derive - * from the presence guard-object macros on the SkipRoot class/constructor, - * which seems well in the weeds for an unmatched-brace syntax error. - * Otherwise the problem is inscrutable, and I haven't found a workaround. - * So for now just disable it when compiling with MSVC -- not ideal, but at - * least Windows debug shell builds complete again. - */ -#ifndef _MSC_VER - { - SkipRoot skip(cx, &v); - MaybeCheckStackRoots(cx); - } -#endif -#endif - JS_ASSERT(!v.isNumber()); goto skip_int_double; for (;;) { diff --git a/js/src/jsnum.h b/js/src/jsnum.h index 87b88b53724..56ec184dd38 100644 --- a/js/src/jsnum.h +++ b/js/src/jsnum.h @@ -151,10 +151,6 @@ StringToNumber(ThreadSafeContext *cx, JSString *str, double *result); MOZ_ALWAYS_INLINE bool ToNumber(JSContext *cx, JS::MutableHandleValue vp) { -#ifdef DEBUG - MaybeCheckStackRoots(cx); -#endif - if (vp.isNumber()) return true; double d; @@ -233,13 +229,6 @@ IsDefinitelyIndex(const Value &v, uint32_t *indexp) static inline bool ToInteger(JSContext *cx, HandleValue v, double *dp) { -#ifdef DEBUG - { - SkipRoot skip(cx, &v); - MaybeCheckStackRoots(cx); - } -#endif - if (v.isInt32()) { *dp = v.toInt32(); return true; diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 0a20d7f3368..472a7ec21ec 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -795,7 +795,7 @@ class AutoPropDescArrayRooter : private AutoGCRooter { public: AutoPropDescArrayRooter(JSContext *cx) - : AutoGCRooter(cx, DESCRIPTORS), descriptors(cx), skip(cx, &descriptors) + : AutoGCRooter(cx, DESCRIPTORS), descriptors(cx) { } PropDesc *append() { @@ -817,7 +817,6 @@ class AutoPropDescArrayRooter : private AutoGCRooter private: PropDescArray descriptors; - SkipRoot skip; }; /* diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h index 4bbf3c44ae9..ad81d85a9c8 100644 --- a/js/src/jspubtd.h +++ b/js/src/jspubtd.h @@ -20,7 +20,7 @@ #include "js/TypeDecls.h" -#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING) || defined(JS_DEBUG) +#if defined(JSGC_USE_EXACT_ROOTING) || defined(JS_DEBUG) # define JSGC_TRACK_EXACT_ROOTS #endif @@ -269,8 +269,6 @@ class ExclusiveContext; class Allocator; -class SkipRoot; - enum ThingRootKind { THING_ROOT_OBJECT, @@ -342,9 +340,6 @@ struct ContextFriendFields { #ifdef JSGC_TRACK_EXACT_ROOTS mozilla::PodArrayZero(thingGCRooters); -#endif -#if defined(JS_DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE) - skipGCRooters = nullptr; #endif } @@ -364,18 +359,6 @@ struct ContextFriendFields JS::Rooted *thingGCRooters[THING_ROOT_LIMIT]; #endif -#if defined(JS_DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE) - /* - * Stack allocated list of stack locations which hold non-relocatable - * GC heap pointers (where the target is rooted somewhere else) or integer - * values which may be confused for GC heap pointers. These are used to - * suppress false positives which occur when a rooting analysis treats the - * location as holding a relocatable pointer, but have no other effect on - * GC behavior. - */ - SkipRoot *skipGCRooters; -#endif - /* Stack of thread-stack-allocated GC roots. */ JS::AutoGCRooter *autoGCRooters; @@ -443,18 +426,6 @@ struct PerThreadDataFriendFields JS::Rooted *thingGCRooters[THING_ROOT_LIMIT]; #endif -#if defined(JS_DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE) - /* - * Stack allocated list of stack locations which hold non-relocatable - * GC heap pointers (where the target is rooted somewhere else) or integer - * values which may be confused for GC heap pointers. These are used to - * suppress false positives which occur when a rooting analysis treats the - * location as holding a relocatable pointer, but have no other effect on - * GC behavior. - */ - SkipRoot *skipGCRooters; -#endif - /* Limit pointer for checking native stack consumption. */ uintptr_t nativeStackLimit[StackKindCount]; diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 4e5c89c10f6..041d9343351 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -1860,7 +1860,8 @@ DoMatchLocal(JSContext *cx, CallArgs args, RegExpStatics *res, HandleupdateFromMatchPairs(cx, input, matches); + if (!res->updateFromMatchPairs(cx, input, matches)) + return false; RootedValue rval(cx); if (!CreateRegExpMatchResult(cx, input, matches, &rval)) @@ -2117,7 +2118,6 @@ struct ReplaceData { ReplaceData(JSContext *cx) : str(cx), g(cx), lambda(cx), elembase(cx), repstr(cx), - dollarRoot(cx, &dollar), dollarEndRoot(cx, &dollarEnd), fig(cx, NullValue()), sb(cx) {} @@ -2147,8 +2147,6 @@ struct ReplaceData Rooted repstr; /* replacement string */ const jschar *dollar; /* null or pointer to first $ in repstr */ const jschar *dollarEnd; /* limit pointer for js_strchr_limit */ - SkipRoot dollarRoot; /* XXX prevent dollar from being relocated */ - SkipRoot dollarEndRoot; /* ditto */ int leftIndex; /* left context index in str->chars */ JSSubString dollarStr; /* for "$$" InterpretDollar result */ bool calledBack; /* record whether callback has been called */ @@ -2175,7 +2173,9 @@ DoMatchForReplaceLocal(JSContext *cx, RegExpStatics *res, HandleupdateFromMatchPairs(cx, linearStr, matches); + if (!res->updateFromMatchPairs(cx, linearStr, matches)) + return false; + return ReplaceRegExp(cx, res, rdata); } @@ -2196,7 +2196,8 @@ DoMatchForReplaceGlobal(JSContext *cx, RegExpStatics *res, HandleupdateFromMatchPairs(cx, linearStr, matches); + if (!res->updateFromMatchPairs(cx, linearStr, matches)) + return false; if (!ReplaceRegExp(cx, res, rdata)) return false; @@ -3293,7 +3294,8 @@ class SplitRegExpMatcher return true; } - res->updateFromMatchPairs(cx, str, matches); + if (!res->updateFromMatchPairs(cx, str, matches)) + return false; JSSubString sep; res->getLastMatch(&sep); diff --git a/js/src/jsstr.h b/js/src/jsstr.h index cb1436bc444..012bed3e519 100644 --- a/js/src/jsstr.h +++ b/js/src/jsstr.h @@ -149,13 +149,6 @@ template static MOZ_ALWAYS_INLINE JSString * ToString(JSContext *cx, JS::HandleValue v) { -#ifdef DEBUG - if (allowGC) { - SkipRoot skip(cx, &v); - MaybeCheckStackRoots(cx); - } -#endif - if (v.isString()) return v.toString(); return ToStringSlow(cx, v); diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 75ba3e298f2..08115d0c12c 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -2720,8 +2720,6 @@ EvalInContext(JSContext *cx, unsigned argc, jsval *vp) if (!src) return false; - SkipRoot skip(cx, &src); - bool lazy = false; if (srclen == 4) { if (src[0] == 'l' && src[1] == 'a' && src[2] == 'z' && src[3] == 'y') { diff --git a/js/src/vm/CharacterEncoding.cpp b/js/src/vm/CharacterEncoding.cpp index 07233163850..b206c2f94a1 100644 --- a/js/src/vm/CharacterEncoding.cpp +++ b/js/src/vm/CharacterEncoding.cpp @@ -333,9 +333,6 @@ typedef bool (*CountAction)(JSContext *, const UTF8Chars, jschar *, size_t *, bo static TwoByteCharsZ InflateUTF8StringHelper(JSContext *cx, const UTF8Chars src, CountAction countAction, size_t *outlen) { - // Malformed UTF8 chars could trigger errors and hence GC. - MaybeCheckStackRoots(cx); - *outlen = 0; bool isAscii; diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 78d431bc0dd..e2ae62028df 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -1711,6 +1711,7 @@ CASE(JSOP_LOOPENTRY) if (status == jit::Method_Error) goto error; if (status == jit::Method_Compiled) { + bool wasSPS = REGS.fp()->hasPushedSPSFrame(); jit::IonExecStatus maybeOsr = jit::EnterBaselineAtBranch(cx, REGS.fp(), REGS.pc); // We failed to call into baseline at all, so treat as an error. @@ -1719,6 +1720,11 @@ CASE(JSOP_LOOPENTRY) interpReturnOK = (maybeOsr == jit::IonExec_Ok); + // Pop the SPS frame pushed by the interpreter. (The compiled version of the + // function popped a copy of the frame pushed by the OSR trampoline.) + if (wasSPS) + cx->runtime()->spsProfiler.exit(script, script->functionNonDelazifying()); + if (activation.entryFrame() != REGS.fp()) goto jit_return_pop_frame; goto leave_on_safe_point; diff --git a/js/src/vm/OldDebugAPI.cpp b/js/src/vm/OldDebugAPI.cpp index 85b491f6ad3..cd26624d116 100644 --- a/js/src/vm/OldDebugAPI.cpp +++ b/js/src/vm/OldDebugAPI.cpp @@ -1306,9 +1306,6 @@ JSAbstractFramePtr::evaluateUCInStackFrame(JSContext *cx, const char *filename, unsigned lineno, MutableHandleValue rval) { - /* Protect inlined chars from root analysis poisoning. */ - SkipRoot skipChars(cx, &chars); - if (!CheckDebugMode(cx)) return false; diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp index a27ede89bef..d7cf8c53773 100644 --- a/js/src/vm/RegExpObject.cpp +++ b/js/src/vm/RegExpObject.cpp @@ -520,9 +520,6 @@ RegExpRunStatus RegExpShared::execute(JSContext *cx, const jschar *chars, size_t length, size_t *lastIndex, MatchPairs &matches) { - /* Protect inlined chars from root analysis poisoning. */ - SkipRoot skip(cx, &chars); - /* Compile the code at point-of-use. */ if (!compileIfNecessary(cx)) return RegExpRunStatus_Error; @@ -576,9 +573,6 @@ RegExpRunStatus RegExpShared::executeMatchOnly(JSContext *cx, const jschar *chars, size_t length, size_t *lastIndex, MatchPair &match) { - /* These chars may be inline in a string. See bug 846011. */ - SkipRoot skipChars(cx, &chars); - /* Compile the code at point-of-use. */ if (!compileMatchOnlyIfNecessary(cx)) return RegExpRunStatus_Error; diff --git a/js/src/vm/RegExpStatics.h b/js/src/vm/RegExpStatics.h index 6ad90810624..335b0f05db7 100644 --- a/js/src/vm/RegExpStatics.h +++ b/js/src/vm/RegExpStatics.h @@ -171,7 +171,7 @@ class AutoRegExpStaticsBuffer : private JS::CustomAutoRooter public: explicit AutoRegExpStaticsBuffer(JSContext *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : CustomAutoRooter(cx), statics(RegExpStatics::InitBuffer()), skip(cx, &statics) + : CustomAutoRooter(cx), statics(RegExpStatics::InitBuffer()) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } @@ -195,7 +195,6 @@ class AutoRegExpStaticsBuffer : private JS::CustomAutoRooter } RegExpStatics statics; - SkipRoot skip; MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index f47d3361b05..bd1539dfd52 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -629,6 +629,7 @@ JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::Runtim #ifdef JSGC_GENERATIONAL rtSizes->gc.nurseryCommitted += gcNursery.sizeOfHeapCommitted(); rtSizes->gc.nurseryDecommitted += gcNursery.sizeOfHeapDecommitted(); + rtSizes->gc.nurseryHugeSlots += gcNursery.sizeOfHugeSlots(mallocSizeOf); gcStoreBuffer.addSizeOfExcludingThis(mallocSizeOf, &rtSizes->gc); #endif } diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index b6b97764734..652fb8cb1c8 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -141,18 +141,6 @@ struct ConservativeGCData */ uintptr_t *nativeStackTop; -#if defined(JSGC_ROOT_ANALYSIS) && (JS_STACK_GROWTH_DIRECTION < 0) - /* - * Record old contents of the native stack from the last time there was a - * scan, to reduce the overhead involved in repeatedly rescanning the - * native stack during root analysis. oldStackData stores words in reverse - * order starting at oldStackEnd. - */ - uintptr_t *oldStackMin, *oldStackEnd; - uintptr_t *oldStackData; - size_t oldStackCapacity; // in sizeof(uintptr_t) -#endif - union { jmp_buf jmpbuf; uintptr_t words[JS_HOWMANY(sizeof(jmp_buf), sizeof(uintptr_t))]; diff --git a/js/src/vm/Shape-inl.h b/js/src/vm/Shape-inl.h index 68d6eb9e022..29d5ffd8f87 100644 --- a/js/src/vm/Shape-inl.h +++ b/js/src/vm/Shape-inl.h @@ -188,8 +188,7 @@ inline AutoRooterGetterSetter::Inner::Inner(ThreadSafeContext *cx, uint8_t attrs, PropertyOp *pgetter_, StrictPropertyOp *psetter_) : CustomAutoRooter(cx), attrs(attrs), - pgetter(pgetter_), psetter(psetter_), - getterRoot(cx, pgetter_), setterRoot(cx, psetter_) + pgetter(pgetter_), psetter(psetter_) { JS_ASSERT_IF(attrs & JSPROP_GETTER, !IsPoisonedPtr(*pgetter)); JS_ASSERT_IF(attrs & JSPROP_SETTER, !IsPoisonedPtr(*psetter)); diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index b3dd8b53fb3..4e09cd9db3e 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -1710,7 +1710,6 @@ EmptyShape::getInitialShape(ExclusiveContext *cx, const Class *clasp, TaggedProt if (p) return p->shape; - SkipRoot skip(cx, &p); /* The hash may look like a GC pointer and get poisoned. */ Rooted protoRoot(cx, proto); RootedObject parentRoot(cx, parent); RootedObject metadataRoot(cx, metadata); diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h index d9a42d5b371..d67e8d71178 100644 --- a/js/src/vm/Shape.h +++ b/js/src/vm/Shape.h @@ -338,7 +338,7 @@ class AutoPropDescRooter : private JS::CustomAutoRooter public: explicit AutoPropDescRooter(JSContext *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : CustomAutoRooter(cx), skip(cx, &propDesc) + : CustomAutoRooter(cx) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } @@ -388,7 +388,6 @@ class AutoPropDescRooter : private JS::CustomAutoRooter virtual void trace(JSTracer *trc); PropDesc propDesc; - SkipRoot skip; MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; @@ -1321,7 +1320,6 @@ class AutoRooterGetterSetter uint8_t attrs; PropertyOp *pgetter; StrictPropertyOp *psetter; - SkipRoot getterRoot, setterRoot; }; public: diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp index bef1beebddc..61ca6919263 100644 --- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -920,7 +920,6 @@ class TypedArrayObjectTemplate : public TypedArrayObject #endif NativeType *dest = static_cast(thisTypedArray->viewData()) + offset; - SkipRoot skipDest(cx, &dest); if (ar->is() && !ar->isIndexed() && ar->getDenseInitializedLength() >= len) { JS_ASSERT(ar->as().length() == len); @@ -931,7 +930,6 @@ class TypedArrayObjectTemplate : public TypedArrayObject * to root |src| and |dest|. */ const Value *src = ar->getDenseElements(); - SkipRoot skipSrc(cx, &src); uint32_t i = 0; do { NativeType n; @@ -1594,7 +1592,6 @@ DataViewObject::write(JSContext *cx, Handle obj, } uint8_t *data; - SkipRoot skipData(cx, &data); if (!getDataPointer(cx, obj, args, sizeof(NativeType), &data)) return false; diff --git a/js/xpconnect/idl/nsIXPCScriptable.idl b/js/xpconnect/idl/nsIXPCScriptable.idl index c5553a2f319..45b66a55882 100644 --- a/js/xpconnect/idl/nsIXPCScriptable.idl +++ b/js/xpconnect/idl/nsIXPCScriptable.idl @@ -160,8 +160,8 @@ class NS_NO_VTABLE nsXPCClassInfo : public nsIClassInfo, public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_XPCCLASSINFO_IID) - NS_IMETHOD_(nsrefcnt) AddRef() = 0; - NS_IMETHOD_(nsrefcnt) Release() = 0; + NS_IMETHOD_(MozExternalRefCountType) AddRef() = 0; + NS_IMETHOD_(MozExternalRefCountType) Release() = 0; virtual void PreserveWrapper(nsISupports *aNative) = 0; diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp index ec2897eb52a..05835484a19 100644 --- a/js/xpconnect/src/XPCComponents.cpp +++ b/js/xpconnect/src/XPCComponents.cpp @@ -3789,8 +3789,8 @@ private: ComponentsSH ComponentsSH::singleton(0); // Singleton refcounting. -NS_IMETHODIMP_(nsrefcnt) ComponentsSH::AddRef(void) { return 1; } -NS_IMETHODIMP_(nsrefcnt) ComponentsSH::Release(void) { return 1; } +NS_IMETHODIMP_(MozExternalRefCountType) ComponentsSH::AddRef(void) { return 1; } +NS_IMETHODIMP_(MozExternalRefCountType) ComponentsSH::Release(void) { return 1; } NS_INTERFACE_MAP_BEGIN(ComponentsSH) NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable) diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index e86286849cc..b0f25929a59 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -2355,6 +2355,11 @@ ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats &rtStats, KIND_NONHEAP, rtStats.runtime.gc.nurseryCommitted, "Memory being used by the GC's nursery."); + RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc/nursery-huge-slots"), + KIND_NONHEAP, rtStats.runtime.gc.nurseryHugeSlots, + "Out-of-line slots and elements belonging to objects in the " + "nursery."); + RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc/store-buffer/vals"), KIND_HEAP, rtStats.runtime.gc.storeBufferVals, "Values in the store buffer."); diff --git a/js/xpconnect/src/XPCShellImpl.cpp b/js/xpconnect/src/XPCShellImpl.cpp index bf324eaf7a8..3c276906001 100644 --- a/js/xpconnect/src/XPCShellImpl.cpp +++ b/js/xpconnect/src/XPCShellImpl.cpp @@ -1654,13 +1654,13 @@ XPCShellDirProvider::SetPluginDir(nsIFile* pluginDir) mPluginDir = pluginDir; } -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) XPCShellDirProvider::AddRef() { return 2; } -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) XPCShellDirProvider::Release() { return 1; diff --git a/js/xpconnect/src/XPCWrappedJS.cpp b/js/xpconnect/src/XPCWrappedJS.cpp index 51c778ae209..8cae27c96e3 100644 --- a/js/xpconnect/src/XPCWrappedJS.cpp +++ b/js/xpconnect/src/XPCWrappedJS.cpp @@ -218,7 +218,7 @@ nsXPCWrappedJS::QueryInterface(REFNSIID aIID, void** aInstancePtr) // For a description of nsXPCWrappedJS lifetime and reference counting, see // the comment at the top of this file. -nsrefcnt +MozExternalRefCountType nsXPCWrappedJS::AddRef(void) { if (!MOZ_LIKELY(NS_IsMainThread())) @@ -237,7 +237,7 @@ nsXPCWrappedJS::AddRef(void) return cnt; } -nsrefcnt +MozExternalRefCountType nsXPCWrappedJS::Release(void) { if (!MOZ_LIKELY(NS_IsMainThread())) diff --git a/js/xpconnect/src/moz.build b/js/xpconnect/src/moz.build index fba85ae96b5..f42d34aecbe 100644 --- a/js/xpconnect/src/moz.build +++ b/js/xpconnect/src/moz.build @@ -93,7 +93,6 @@ LOCAL_INCLUDES += [ '/js/ipc', '/layout/base', '/layout/style', - '/xpcom/ds', ] if CONFIG['MOZ_B2G_BT']: diff --git a/layout/base/Units.h b/layout/base/Units.h index ba3c37bc321..4ad4391f098 100644 --- a/layout/base/Units.h +++ b/layout/base/Units.h @@ -261,6 +261,18 @@ gfx::SizeTyped operator/(const gfx::SizeTyped& aSize, const gfx::Scale aSize.height / aScale.scale); } +template +gfx::SizeTyped operator*(const gfx::IntSizeTyped& aSize, const gfx::ScaleFactor& aScale) { + return gfx::SizeTyped(float(aSize.width) * aScale.scale, + float(aSize.height) * aScale.scale); +} + +template +gfx::SizeTyped operator/(const gfx::IntSizeTyped& aSize, const gfx::ScaleFactor& aScale) { + return gfx::SizeTyped(float(aSize.width) / aScale.scale, + float(aSize.height) / aScale.scale); +} + template gfx::MarginTyped operator*(const gfx::MarginTyped& aMargin, const gfx::ScaleFactor& aScale) { return gfx::MarginTyped(aMargin.top * aScale.scale, diff --git a/layout/base/moz.build b/layout/base/moz.build index 5095f56661a..0b08f347b2d 100644 --- a/layout/base/moz.build +++ b/layout/base/moz.build @@ -132,7 +132,6 @@ LOCAL_INCLUDES += [ '/dom/base', '/dom/events', '/dom/xbl', - '/xpcom/ds', ] FINAL_LIBRARY = 'gklayout' diff --git a/layout/base/nsIPresShell.h b/layout/base/nsIPresShell.h index e90b3fb644d..47b2a58f86d 100644 --- a/layout/base/nsIPresShell.h +++ b/layout/base/nsIPresShell.h @@ -168,17 +168,11 @@ enum nsRectVisibility { * frame. */ -// hack to make egcs / gcc 2.95.2 happy -class nsIPresShell_base : public nsISupports +class nsIPresShell : public nsISupports { public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_IPRESSHELL_IID) -}; -NS_DEFINE_STATIC_IID_ACCESSOR(nsIPresShell_base, NS_IPRESSHELL_IID) - -class nsIPresShell : public nsIPresShell_base -{ protected: typedef mozilla::layers::LayerManager LayerManager; typedef mozilla::gfx::SourceSurface SourceSurface; @@ -1646,4 +1640,6 @@ protected: bool mIsNeverPainting; }; +NS_DEFINE_STATIC_IID_ACCESSOR(nsIPresShell, NS_IPRESSHELL_IID) + #endif /* nsIPresShell_h___ */ diff --git a/layout/base/nsRefreshDriver.h b/layout/base/nsRefreshDriver.h index fcfd2b2522d..57ed0b2c7b0 100644 --- a/layout/base/nsRefreshDriver.h +++ b/layout/base/nsRefreshDriver.h @@ -45,8 +45,8 @@ public: // // The refresh driver does NOT hold references to refresh observers // except while it is notifying them. - NS_IMETHOD_(nsrefcnt) AddRef(void) = 0; - NS_IMETHOD_(nsrefcnt) Release(void) = 0; + NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0; + NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0; virtual void WillRefresh(mozilla::TimeStamp aTime) = 0; }; diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index 12368eccdcc..f3d34758678 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -1545,6 +1545,14 @@ public: static ScrollFrameActivityTracker *gScrollFrameActivityTracker = nullptr; +// There are situations when a scroll frame is destroyed and then re-created +// for the same content element. In this case we want to increment the scroll +// generation between the old and new scrollframes. If the new one knew about +// the old one then it could steal the old generation counter and increment it +// but it doesn't have that reference so instead we use a static global to +// ensure the new one gets a fresh value. +static uint32_t sScrollGenerationCounter = 0; + ScrollFrameHelper::ScrollFrameHelper(nsContainerFrame* aOuter, bool aIsRoot) : mHScrollbarBox(nullptr) @@ -1555,7 +1563,7 @@ ScrollFrameHelper::ScrollFrameHelper(nsContainerFrame* aOuter, , mOuter(aOuter) , mAsyncScroll(nullptr) , mOriginOfLastScroll(nsGkAtoms::other) - , mScrollGeneration(0) + , mScrollGeneration(++sScrollGenerationCounter) , mDestination(0, 0) , mScrollPosAtLastPaint(0, 0) , mRestorePos(-1, -1) @@ -2071,7 +2079,7 @@ ScrollFrameHelper::ScrollToImpl(nsPoint aPt, const nsRect& aRange, nsIAtom* aOri // Update frame position for scrolling mScrolledFrame->SetPosition(mScrollPort.TopLeft() - pt); mOriginOfLastScroll = aOrigin; - mScrollGeneration++; + mScrollGeneration = ++sScrollGenerationCounter; // We pass in the amount to move visually ScrollVisual(oldScrollFramePos); diff --git a/layout/reftests/svg/filters/feTurbulence-offset-ref.svg b/layout/reftests/svg/filters/feTurbulence-offset-ref.svg new file mode 100644 index 00000000000..fbfaf840af1 --- /dev/null +++ b/layout/reftests/svg/filters/feTurbulence-offset-ref.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/layout/reftests/svg/filters/feTurbulence-offset.svg b/layout/reftests/svg/filters/feTurbulence-offset.svg new file mode 100644 index 00000000000..c48db258b33 --- /dev/null +++ b/layout/reftests/svg/filters/feTurbulence-offset.svg @@ -0,0 +1,20 @@ + + + + + + + + + diff --git a/layout/reftests/svg/filters/reftest.list b/layout/reftests/svg/filters/reftest.list index 30ee93b50ff..070c04b30aa 100644 --- a/layout/reftests/svg/filters/reftest.list +++ b/layout/reftests/svg/filters/reftest.list @@ -101,6 +101,8 @@ fuzzy(2,2659) skip-if(d2d) == feSpecularLighting-1.svg feSpecularLighting-1-ref. == fePointLight-zoomed-page.svg fePointLight-zoomed-page-ref.svg +== feTurbulence-offset.svg feTurbulence-offset-ref.svg + pref(layout.css.filters.enabled,true) == multiple-svg-filters.svg multiple-svg-filters-ref.svg pref(layout.css.filters.enabled,true) == multiple-svg-filters-long-chain.svg multiple-svg-filters-ref.svg pref(layout.css.filters.enabled,true) == multiple-svg-filters-second-uses-SourceGraphic.svg multiple-svg-filters-ref.svg diff --git a/layout/reftests/svg/reftest.list b/layout/reftests/svg/reftest.list index 57b40add60d..c4e9c2245ca 100644 --- a/layout/reftests/svg/reftest.list +++ b/layout/reftests/svg/reftest.list @@ -95,7 +95,7 @@ skip-if(B2G) == dynamic-pattern-02.svg pass.svg skip-if(B2G) == dynamic-pattern-contents-01.svg pass.svg skip-if(B2G) == dynamic-pattern-contents-02.svg pass.svg == dynamic-rect-01.svg dynamic-rect-01-ref.svg -== dynamic-rect-02.svg dynamic-rect-02-ref.svg +fuzzy-if(d2d&&layersGPUAccelerated,3,1200) == dynamic-rect-02.svg dynamic-rect-02-ref.svg # bug 776038 for Win7, Win8 == dynamic-rect-03.svg dynamic-rect-03-ref.svg == dynamic-rect-04.xhtml pass.svg == dynamic-rect-05.svg pass.svg @@ -107,7 +107,7 @@ skip-if(B2G) == dynamic-pattern-contents-02.svg pass.svg == dynamic-stroke-width-01.svg pass.svg == dynamic-switch-01.svg pass.svg == dynamic-text-01.svg dynamic-text-01-ref.svg -fuzzy-if(d2d&&layersGPUAccelerated,2,12739) == dynamic-text-02.svg dynamic-text-02-ref.svg # bug 776038 for Win7 +fuzzy-if(d2d&&layersGPUAccelerated,3,12739) == dynamic-text-02.svg dynamic-text-02-ref.svg # bug 776038 for Win7, Win8 fuzzy-if(d2d&&layersGPUAccelerated,2,10539) == dynamic-text-03.svg dynamic-text-03-ref.svg # bug 776038 for Win7 random-if(/^Windows\x20NT\x205\.1/.test(http.oscpu)) fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu),47,89) == dynamic-text-04.svg dynamic-text-04-ref.svg # bug 421587 for WinXP, bug 776038 for Win7 skip-if(B2G) == dynamic-text-05.svg pass.svg diff --git a/layout/style/NameSpaceRule.h b/layout/style/NameSpaceRule.h index 1df6212da39..1106bae5fbc 100644 --- a/layout/style/NameSpaceRule.h +++ b/layout/style/NameSpaceRule.h @@ -64,9 +64,9 @@ private: nsString mURLSpec; }; +NS_DEFINE_STATIC_IID_ACCESSOR(NameSpaceRule, NS_CSS_NAMESPACE_RULE_IMPL_CID) + } // namespace css } // namespace mozilla -NS_DEFINE_STATIC_IID_ACCESSOR(mozilla::css::NameSpaceRule, NS_CSS_NAMESPACE_RULE_IMPL_CID) - #endif /* mozilla_css_NameSpaceRule_h__ */ diff --git a/layout/style/StyleRule.h b/layout/style/StyleRule.h index 11763749445..98e48ebc75b 100644 --- a/layout/style/StyleRule.h +++ b/layout/style/StyleRule.h @@ -382,9 +382,9 @@ private: StyleRule& operator=(const StyleRule& aCopy) MOZ_DELETE; }; +NS_DEFINE_STATIC_IID_ACCESSOR(StyleRule, NS_CSS_STYLE_RULE_IMPL_CID) + } // namespace css } // namespace mozilla -NS_DEFINE_STATIC_IID_ACCESSOR(mozilla::css::StyleRule, NS_CSS_STYLE_RULE_IMPL_CID) - #endif /* mozilla_css_StyleRule_h__ */ diff --git a/layout/style/nsDOMCSSDeclaration.h b/layout/style/nsDOMCSSDeclaration.h index 8cb35708aae..027e7c598e6 100644 --- a/layout/style/nsDOMCSSDeclaration.h +++ b/layout/style/nsDOMCSSDeclaration.h @@ -36,8 +36,8 @@ public: // Declare addref and release so they can be called on us, but don't // implement them. Our subclasses must handle their own // refcounting. - NS_IMETHOD_(nsrefcnt) AddRef() MOZ_OVERRIDE = 0; - NS_IMETHOD_(nsrefcnt) Release() MOZ_OVERRIDE = 0; + NS_IMETHOD_(MozExternalRefCountType) AddRef() MOZ_OVERRIDE = 0; + NS_IMETHOD_(MozExternalRefCountType) Release() MOZ_OVERRIDE = 0; NS_DECL_NSICSSDECLARATION using nsICSSDeclaration::GetLength; diff --git a/layout/svg/nsFilterInstance.cpp b/layout/svg/nsFilterInstance.cpp index 2685f7fa956..5debe7efcb5 100644 --- a/layout/svg/nsFilterInstance.cpp +++ b/layout/svg/nsFilterInstance.cpp @@ -118,7 +118,12 @@ nsFilterInstance::nsFilterInstance(nsIFrame *aTargetFrame, mTargetBBox = aOverrideBBox ? *aOverrideBBox : nsSVGUtils::GetBBox(mTargetFrame); - nsresult rv = BuildPrimitives(); + nsresult rv = ComputeUserSpaceToFilterSpaceScale(); + if (NS_FAILED(rv)) { + return; + } + + rv = BuildPrimitives(); if (NS_FAILED(rv)) { return; } @@ -130,9 +135,9 @@ nsFilterInstance::nsFilterInstance(nsIFrame *aTargetFrame, // Get various transforms: - gfxMatrix filterToUserSpace(mFilterRegion.Width() / mFilterSpaceBounds.width, 0.0f, - 0.0f, mFilterRegion.Height() / mFilterSpaceBounds.height, - mFilterRegion.X(), mFilterRegion.Y()); + gfxMatrix filterToUserSpace(mFilterSpaceToUserSpaceScale.width, 0.0f, + 0.0f, mFilterSpaceToUserSpaceScale.height, + 0.0f, 0.0f); // Only used (so only set) when we paint: if (mPaintCallback) { @@ -164,23 +169,44 @@ nsFilterInstance::nsFilterInstance(nsIFrame *aTargetFrame, mInitialized = true; } -gfxRect -nsFilterInstance::UserSpaceToFilterSpace(const gfxRect& aRect) const +nsresult +nsFilterInstance::ComputeUserSpaceToFilterSpaceScale() { - gfxRect r = aRect - mFilterRegion.TopLeft(); - r.Scale(mFilterSpaceBounds.width / mFilterRegion.Width(), - mFilterSpaceBounds.height / mFilterRegion.Height()); - return r; + gfxMatrix canvasTransform = + nsSVGUtils::GetCanvasTM(mTargetFrame, nsISVGChildFrame::FOR_OUTERSVG_TM); + if (canvasTransform.IsSingular()) { + // Nothing should be rendered. + return NS_ERROR_FAILURE; + } + + mUserSpaceToFilterSpaceScale = canvasTransform.ScaleFactors(true); + if (mUserSpaceToFilterSpaceScale.width <= 0.0f || + mUserSpaceToFilterSpaceScale.height <= 0.0f) { + // Nothing should be rendered. + return NS_ERROR_FAILURE; + } + + mFilterSpaceToUserSpaceScale = gfxSize(1.0f / mUserSpaceToFilterSpaceScale.width, + 1.0f / mUserSpaceToFilterSpaceScale.height); + return NS_OK; } -gfxMatrix -nsFilterInstance::GetUserSpaceToFilterSpaceTransform() const +gfxRect +nsFilterInstance::UserSpaceToFilterSpace(const gfxRect& aUserSpaceRect) const { - gfxFloat widthScale = mFilterSpaceBounds.width / mFilterRegion.Width(); - gfxFloat heightScale = mFilterSpaceBounds.height / mFilterRegion.Height(); - return gfxMatrix(widthScale, 0.0f, - 0.0f, heightScale, - -mFilterRegion.X() * widthScale, -mFilterRegion.Y() * heightScale); + gfxRect filterSpaceRect = aUserSpaceRect; + filterSpaceRect.Scale(mUserSpaceToFilterSpaceScale.width, + mUserSpaceToFilterSpaceScale.height); + return filterSpaceRect; +} + +gfxRect +nsFilterInstance::FilterSpaceToUserSpace(const gfxRect& aFilterSpaceRect) const +{ + gfxRect userSpaceRect = aFilterSpaceRect; + userSpaceRect.Scale(mFilterSpaceToUserSpaceScale.width, + mFilterSpaceToUserSpaceScale.height); + return userSpaceRect; } nsresult @@ -202,9 +228,15 @@ nsFilterInstance::BuildPrimitives() nsresult nsFilterInstance::BuildPrimitivesForFilter(const nsStyleFilter& aFilter) { + NS_ASSERTION(mUserSpaceToFilterSpaceScale.width > 0.0f && + mFilterSpaceToUserSpaceScale.height > 0.0f, + "scale factors between spaces should be positive values"); + if (aFilter.GetType() == NS_STYLE_FILTER_URL) { // Build primitives for an SVG filter. - nsSVGFilterInstance svgFilterInstance(aFilter, mTargetFrame, mTargetBBox); + nsSVGFilterInstance svgFilterInstance(aFilter, mTargetFrame, mTargetBBox, + mUserSpaceToFilterSpaceScale, + mFilterSpaceToUserSpaceScale); if (!svgFilterInstance.IsInitialized()) { return NS_ERROR_FAILURE; } @@ -212,7 +244,7 @@ nsFilterInstance::BuildPrimitivesForFilter(const nsStyleFilter& aFilter) // For now, we use the last SVG filter region as the overall filter region // for the filter chain. Eventually, we will compute the overall filter // using all of the generated FilterPrimitiveDescriptions. - mFilterRegion = svgFilterInstance.GetFilterRegion(); + mUserSpaceBounds = svgFilterInstance.GetFilterRegion(); mFilterSpaceBounds = svgFilterInstance.GetFilterSpaceBounds(); // If this overflows, we can at least paint the maximum surface size. @@ -289,10 +321,6 @@ nsFilterInstance::BuildSourcePaint(SourceInfo *aSource, nsRenderingContext tmpCtx; tmpCtx.Init(mTargetFrame->PresContext()->DeviceContext(), ctx); - gfxMatrix m = GetUserSpaceToFilterSpaceTransform(); - m.Invert(); - gfxRect r = m.TransformBounds(mFilterSpaceBounds); - gfxMatrix deviceToFilterSpace = GetFilterSpaceToDeviceSpaceTransform().Invert(); gfxContext *gfx = tmpCtx.ThebesContext(); gfx->Multiply(deviceToFilterSpace); @@ -304,7 +332,7 @@ nsFilterInstance::BuildSourcePaint(SourceInfo *aSource, mTransformRoot); if (!matrix.IsSingular()) { gfx->Multiply(matrix); - gfx->Rectangle(r); + gfx->Rectangle(mUserSpaceBounds); if ((aSource == &mFillPaint && nsSVGUtils::SetupCairoFillPaint(mTargetFrame, gfx)) || (aSource == &mStrokePaint && @@ -376,9 +404,7 @@ nsFilterInstance::BuildSourceImage(gfxASurface* aTargetSurface, nsRenderingContext tmpCtx; tmpCtx.Init(mTargetFrame->PresContext()->DeviceContext(), ctx); - gfxMatrix m = GetUserSpaceToFilterSpaceTransform(); - m.Invert(); - gfxRect r = m.TransformBounds(neededRect); + gfxRect r = FilterSpaceToUserSpace(neededRect); r.RoundOut(); nsIntRect dirty; if (!gfxUtils::GfxRectToIntRect(r, &dirty)) diff --git a/layout/svg/nsFilterInstance.h b/layout/svg/nsFilterInstance.h index 475ea1876aa..0712eb2197e 100644 --- a/layout/svg/nsFilterInstance.h +++ b/layout/svg/nsFilterInstance.h @@ -155,11 +155,6 @@ public: */ nsresult ComputeSourceNeededRect(nsRect* aDirty); - /** - * Returns the transform from the filtered element's user space to filter - * space. This will be a simple translation and/or scale. - */ - gfxMatrix GetUserSpaceToFilterSpaceTransform() const; /** * Returns the transform from filter space to outer- device space. @@ -227,7 +222,16 @@ private: */ void ComputeNeededBoxes(); + /** + * Compute the scale factors between user space and filter space. + */ + nsresult ComputeUserSpaceToFilterSpaceScale(); + + /** + * Transform a rect between user space and filter space. + */ gfxRect UserSpaceToFilterSpace(const gfxRect& aUserSpace) const; + gfxRect FilterSpaceToUserSpace(const gfxRect& aFilterSpaceRect) const; /** * Converts an nsRect that is relative to a filtered frame's origin (i.e. the @@ -271,9 +275,15 @@ private: /** * The "filter region", in the filtered element's user space. */ - gfxRect mFilterRegion; + gfxRect mUserSpaceBounds; nsIntRect mFilterSpaceBounds; + /** + * The scale factors between user space and filter space. + */ + gfxSize mUserSpaceToFilterSpaceScale; + gfxSize mFilterSpaceToUserSpaceScale; + /** * Pre-filter paint bounds of the element that is being filtered, in filter * space. diff --git a/layout/svg/nsSVGFilterInstance.cpp b/layout/svg/nsSVGFilterInstance.cpp index 89118dcf6b1..b6c6be4d623 100644 --- a/layout/svg/nsSVGFilterInstance.cpp +++ b/layout/svg/nsSVGFilterInstance.cpp @@ -26,10 +26,14 @@ using namespace mozilla::gfx; nsSVGFilterInstance::nsSVGFilterInstance(const nsStyleFilter& aFilter, nsIFrame *aTargetFrame, - const gfxRect& aTargetBBox) : + const gfxRect& aTargetBBox, + const gfxSize& aUserSpaceToFilterSpaceScale, + const gfxSize& aFilterSpaceToUserSpaceScale) : mFilter(aFilter), mTargetFrame(aTargetFrame), mTargetBBox(aTargetBBox), + mUserSpaceToFilterSpaceScale(aUserSpaceToFilterSpaceScale), + mFilterSpaceToUserSpaceScale(aFilterSpaceToUserSpaceScale), mInitialized(false) { // Get the filter frame. @@ -48,12 +52,7 @@ nsSVGFilterInstance::nsSVGFilterInstance(const nsStyleFilter& aFilter, mPrimitiveUnits = mFilterFrame->GetEnumValue(SVGFilterElement::PRIMITIVEUNITS); - nsresult rv = ComputeUserSpaceToIntermediateSpaceScale(); - if (NS_FAILED(rv)) { - return; - } - - rv = ComputeBounds(); + nsresult rv = ComputeBounds(); if (NS_FAILED(rv)) { return; } @@ -61,21 +60,6 @@ nsSVGFilterInstance::nsSVGFilterInstance(const nsStyleFilter& aFilter, mInitialized = true; } -nsresult -nsSVGFilterInstance::ComputeUserSpaceToIntermediateSpaceScale() -{ - gfxMatrix canvasTransform = - nsSVGUtils::GetCanvasTM(mTargetFrame, nsISVGChildFrame::FOR_OUTERSVG_TM); - if (canvasTransform.IsSingular()) { - // Nothing should be rendered. - return NS_ERROR_FAILURE; - } - mUserSpaceToIntermediateSpaceScale = canvasTransform.ScaleFactors(true); - mIntermediateSpaceToUserSpaceScale = gfxSize(1.0 / mUserSpaceToIntermediateSpaceScale.width, - 1.0 / mUserSpaceToIntermediateSpaceScale.height); - return NS_OK; -} - nsresult nsSVGFilterInstance::ComputeBounds() { @@ -104,10 +88,10 @@ nsSVGFilterInstance::ComputeBounds() mUserSpaceBounds = nsSVGUtils::GetRelativeRect(filterUnits, XYWH, mTargetBBox, mTargetFrame); - // Temporarily transform the user space bounds to intermediate space, so we + // Temporarily transform the user space bounds to filter space, so we // can align them with the pixel boundries of the offscreen surface. - // The offscreen surface has the same scale as intermediate space. - mUserSpaceBounds = UserSpaceToIntermediateSpace(mUserSpaceBounds); + // The offscreen surface has the same scale as filter space. + mUserSpaceBounds = UserSpaceToFilterSpace(mUserSpaceBounds); mUserSpaceBounds.RoundOut(); if (mUserSpaceBounds.Width() <= 0 || mUserSpaceBounds.Height() <= 0) { // 0 disables rendering, < 0 is error. dispatch error console warning @@ -115,18 +99,14 @@ nsSVGFilterInstance::ComputeBounds() return NS_ERROR_FAILURE; } - // Set the intermediate space bounds. - if (!gfxUtils::GfxRectToIntRect(mUserSpaceBounds, &mIntermediateSpaceBounds)) { + // Set the filter space bounds. + if (!gfxUtils::GfxRectToIntRect(mUserSpaceBounds, &mFilterSpaceBounds)) { // The filter region is way too big if there is float -> int overflow. return NS_ERROR_FAILURE; } - // Set the filter space bounds. - mFilterSpaceBounds = mIntermediateSpaceBounds; - mFilterSpaceBounds.MoveTo(0, 0); - // Undo the temporary transformation of the user space bounds. - mUserSpaceBounds = IntermediateSpaceToUserSpace(mUserSpaceBounds); + mUserSpaceBounds = FilterSpaceToUserSpace(mUserSpaceBounds); return NS_OK; } @@ -189,14 +169,14 @@ nsSVGFilterInstance::GetPrimitiveNumber(uint8_t aCtxType, float aValue) const switch (aCtxType) { case SVGContentUtils::X: - return value * mUserSpaceToIntermediateSpaceScale.width; + return value * mUserSpaceToFilterSpaceScale.width; case SVGContentUtils::Y: - return value * mUserSpaceToIntermediateSpaceScale.height; + return value * mUserSpaceToFilterSpaceScale.height; case SVGContentUtils::XY: default: return value * SVGContentUtils::ComputeNormalizedHypotenuse( - mUserSpaceToIntermediateSpaceScale.width, - mUserSpaceToIntermediateSpaceScale.height); + mUserSpaceToFilterSpaceScale.width, + mUserSpaceToFilterSpaceScale.height); } } @@ -223,24 +203,18 @@ nsSVGFilterInstance::ConvertLocation(const Point3D& aPoint) const gfxRect nsSVGFilterInstance::UserSpaceToFilterSpace(const gfxRect& aUserSpaceRect) const { - return UserSpaceToIntermediateSpace(aUserSpaceRect - mUserSpaceBounds.TopLeft()); + gfxRect filterSpaceRect = aUserSpaceRect; + filterSpaceRect.Scale(mUserSpaceToFilterSpaceScale.width, + mUserSpaceToFilterSpaceScale.height); + return filterSpaceRect; } gfxRect -nsSVGFilterInstance::UserSpaceToIntermediateSpace(const gfxRect& aUserSpaceRect) const +nsSVGFilterInstance::FilterSpaceToUserSpace(const gfxRect& aFilterSpaceRect) const { - gfxRect intermediateSpaceRect = aUserSpaceRect; - intermediateSpaceRect.Scale(mUserSpaceToIntermediateSpaceScale.width, - mUserSpaceToIntermediateSpaceScale.height); - return intermediateSpaceRect; -} - -gfxRect -nsSVGFilterInstance::IntermediateSpaceToUserSpace(const gfxRect& aIntermediateSpaceRect) const -{ - gfxRect userSpaceRect = aIntermediateSpaceRect; - userSpaceRect.Scale(mIntermediateSpaceToUserSpaceScale.width, - mIntermediateSpaceToUserSpaceScale.height); + gfxRect userSpaceRect = aFilterSpaceRect; + userSpaceRect.Scale(mFilterSpaceToUserSpaceScale.width, + mFilterSpaceToUserSpaceScale.height); return userSpaceRect; } diff --git a/layout/svg/nsSVGFilterInstance.h b/layout/svg/nsSVGFilterInstance.h index fe01e4607f2..5a49565c0c1 100644 --- a/layout/svg/nsSVGFilterInstance.h +++ b/layout/svg/nsSVGFilterInstance.h @@ -39,20 +39,15 @@ class SVGFilterElement; * CSS pixel space. The origin for an HTML element is the top left corner of * its border box. * - * "intermediate space" + * "filter space" * User space scaled to device pixels. Shares the same origin as user space. * This space is the same across chained SVG and CSS filters. To compute the * overall filter space for a chain, we first need to build each filter's * FilterPrimitiveDescriptions in some common space. That space is - * intermediate space. + * filter space. * - * "filter space" - * Intermediate space translated to the origin of this SVG filter's - * filter region. This space may be different for each filter in a chain. - * - * To understand the spaces better, let's take an example filter that defines a - * filter region: - * ... + * To understand the spaces better, let's take an example filter: + * ... * * And apply the filter to a div element: *
...
@@ -65,21 +60,10 @@ class SVGFilterElement; * The point will be inset 10 CSS pixels from both the top and left edges of the * div element's border box. * - * Now, let's transform the point from user space to intermediate space: - * "intermediate space point" = "user space point" * "device pixels per CSS pixel" - * "intermediate space point" = (10, 10) * 2 - * "intermediate space point" = (20, 20) - * - * Next, let's transform the point from user space to filter space: - * "filter space point" = ("user space point" - "filter region position in user space") * "device pixels per CSS pixel" - * "filter space point" = ((10, 10) - (-15, -15)) * 2 - * "filter space point" = (50, 50) - * - * Similarly, we can convert the point from intermediate space to filter space: - * "filter space point" = "intermediate space point" - "filter region position in intermediate space" - * "filter space point" = "intermediate space point" - ("filter region position in user space" * "device pixels per CSS pixel") - * "filter space point" = (20, 20) - ((-15, -15) * 2) - * "filter space point" = (50, 50) + * Now, let's transform the point from user space to filter space: + * "filter space point" = "user space point" * "device pixels per CSS pixel" + * "filter space point" = (10, 10) * 2 + * "filter space point" = (20, 20) */ class nsSVGFilterInstance { @@ -97,7 +81,9 @@ public: */ nsSVGFilterInstance(const nsStyleFilter& aFilter, nsIFrame *aTargetFrame, - const gfxRect& aTargetBBox); + const gfxRect& aTargetBBox, + const gfxSize& aUserSpaceToFilterSpaceScale, + const gfxSize& aFilterSpaceToUserSpaceScale); /** * Returns true if the filter instance was created successfully. @@ -176,10 +162,9 @@ private: float GetPrimitiveNumber(uint8_t aCtxType, float aValue) const; /** - * Transform a rect between user space and intermediate space. + * Transform a rect between user space and filter space. */ - gfxRect UserSpaceToIntermediateSpace(const gfxRect& aUserSpaceRect) const; - gfxRect IntermediateSpaceToUserSpace(const gfxRect& aIntermediateSpaceRect) const; + gfxRect FilterSpaceToUserSpace(const gfxRect& aFilterSpaceRect) const; /** * Returns the transform from frame space to the coordinate space that @@ -201,12 +186,7 @@ private: nsTArray& aSourceIndices); /** - * Compute the scale factors between user space and intermediate space. - */ - nsresult ComputeUserSpaceToIntermediateSpaceScale(); - - /** - * Compute the filter region in user space, intermediate space, and filter + * Compute the filter region in user space, filter space, and filter * space. */ nsresult ComputeBounds(); @@ -240,14 +220,13 @@ private: * The "filter region" in various spaces. */ gfxRect mUserSpaceBounds; - nsIntRect mIntermediateSpaceBounds; nsIntRect mFilterSpaceBounds; /** - * The scale factors between user space and intermediate space. + * The scale factors between user space and filter space. */ - gfxSize mUserSpaceToIntermediateSpaceScale; - gfxSize mIntermediateSpaceToUserSpaceScale; + gfxSize mUserSpaceToFilterSpaceScale; + gfxSize mFilterSpaceToUserSpaceScale; /** * The 'primitiveUnits' attribute value (objectBoundingBox or userSpaceOnUse). diff --git a/media/libopus/moz.build b/media/libopus/moz.build index fb654462f05..3d653903bae 100644 --- a/media/libopus/moz.build +++ b/media/libopus/moz.build @@ -67,3 +67,9 @@ else: 'silk/fixed', ] SOURCES += silk_sources_fixed + +# Suppress warnings in third-party code. +if CONFIG['GNU_CC']: + CFLAGS += ['-Wno-declaration-after-statement'] + if CONFIG['CLANG_CXX']: + CFLAGS += ['-Wno-\#pragma-messages'] diff --git a/media/libtheora/lib/moz.build b/media/libtheora/lib/moz.build index 648b98fae14..6f834fda05a 100644 --- a/media/libtheora/lib/moz.build +++ b/media/libtheora/lib/moz.build @@ -78,5 +78,7 @@ FINAL_LIBRARY = 'gkmedias' DEFINES['THEORA_DISABLE_ENCODE'] = True # Suppress warnings in third-party code. -if CONFIG['CLANG_CXX']: - CFLAGS += ['-Wno-tautological-compare'] +if CONFIG['GNU_CC']: + CFLAGS += ['-Wno-type-limits'] + if CONFIG['CLANG_CXX']: + CFLAGS += ['-Wno-tautological-compare'] diff --git a/media/mtransport/nr_socket_prsock.h b/media/mtransport/nr_socket_prsock.h index 6614b0520bb..ffd2e75aa3e 100644 --- a/media/mtransport/nr_socket_prsock.h +++ b/media/mtransport/nr_socket_prsock.h @@ -101,8 +101,8 @@ public: virtual int cancel(int how); // nsISupport reference counted interface - NS_IMETHOD_(nsrefcnt) AddRef(void) = 0; - NS_IMETHOD_(nsrefcnt) Release(void) = 0; + NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0; + NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0; uint32_t poll_flags() { return poll_flags_; diff --git a/mfbt/RefCountType.h b/mfbt/RefCountType.h index 7d304b6c2e0..e95a22a0ca6 100644 --- a/mfbt/RefCountType.h +++ b/mfbt/RefCountType.h @@ -7,26 +7,31 @@ #ifndef mozilla_RefCountType_h #define mozilla_RefCountType_h +#include + /** * MozRefCountType is Mozilla's reference count type. * - * This is the return type for AddRef() and Release() in nsISupports. - * IUnknown of COM returns an unsigned long from equivalent functions. - * * We use the same type to represent the refcount of RefCounted objects * as well, in order to be able to use the leak detection facilities * that are implemented by XPCOM. * - * The following ifdef exists to maintain binary compatibility with - * IUnknown, the base interface in Microsoft COM. - * * Note that this type is not in the mozilla namespace so that it is * usable for both C and C++ code. */ +typedef uintptr_t MozRefCountType; + +/* + * This is the return type for AddRef() and Release() in nsISupports. + * IUnknown of COM returns an unsigned long from equivalent functions. + * + * The following ifdef exists to maintain binary compatibility with + * IUnknown, the base interface in Microsoft COM. + */ #ifdef XP_WIN -typedef unsigned long MozRefCountType; +typedef unsigned long MozExternalRefCountType; #else -typedef uint32_t MozRefCountType; +typedef uint32_t MozExternalRefCountType; #endif #endif diff --git a/mfbt/WeakPtr.h b/mfbt/WeakPtr.h index 97c5c6e693a..9802ce5b585 100644 --- a/mfbt/WeakPtr.h +++ b/mfbt/WeakPtr.h @@ -14,6 +14,8 @@ * the WeakPtrs to it and allows the WeakReference to live beyond the lifetime * of 'Foo'. * + * PLEASE NOTE: This weak pointer implementation is not thread-safe. + * * Note that when deriving from SupportsWeakPtr you should add * MOZ_DECLARE_REFCOUNTED_TYPENAME(ClassName) to the public section of your * class, where ClassName is the name of your class. diff --git a/mobile/android/components/MobileComponents.manifest b/mobile/android/components/MobileComponents.manifest index 50174be1e47..3972529c4ee 100644 --- a/mobile/android/components/MobileComponents.manifest +++ b/mobile/android/components/MobileComponents.manifest @@ -27,8 +27,6 @@ category xpcom-directory-providers browser-directory-provider @mozilla.org/brows # Sidebar.js component {22117140-9c6e-11d3-aaf1-00805f8a4905} Sidebar.js contract @mozilla.org/sidebar;1 {22117140-9c6e-11d3-aaf1-00805f8a4905} -category JavaScript-global-property sidebar @mozilla.org/sidebar;1 -category JavaScript-global-property external @mozilla.org/sidebar;1 category wakeup-request Sidebar @mozilla.org/sidebar;1,nsISidebarExternal,getService,Sidebar:AddSearchProvider # SessionStore.js diff --git a/mobile/android/components/Sidebar.js b/mobile/android/components/Sidebar.js index 8f8ee29db57..5f6b26408c8 100644 --- a/mobile/android/components/Sidebar.js +++ b/mobile/android/components/Sidebar.js @@ -91,7 +91,6 @@ Sidebar.prototype = { Services.search.addEngine(engineURL, dataType, iconURL, true); }, - // =========================== nsISidebarExternal =========================== // This function exists to implement window.external.AddSearchProvider(), // to match other browsers' APIs. The capitalization, although nonstandard here, // is therefore important. @@ -121,17 +120,8 @@ Sidebar.prototype = { return 0; }, - // =========================== nsIClassInfo =========================== - classInfo: XPCOMUtils.generateCI({classID: SIDEBAR_CID, - contractID: SIDEBAR_CONTRACTID, - interfaces: [Ci.nsISidebar, - Ci.nsISidebarExternal], - flags: Ci.nsIClassInfo.DOM_OBJECT, - classDescription: "Sidebar"}), - // =========================== nsISupports =========================== - QueryInterface: XPCOMUtils.generateQI([Ci.nsISidebar, - Ci.nsISidebarExternal]), + QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]), // XPCOMUtils stuff classID: SIDEBAR_CID, diff --git a/mobile/android/config/mozconfigs/android-armv6/debug b/mobile/android/config/mozconfigs/android-armv6/debug index 9d6e21cb4cf..4a1f0da90a0 100644 --- a/mobile/android/config/mozconfigs/android-armv6/debug +++ b/mobile/android/config/mozconfigs/android-armv6/debug @@ -8,7 +8,6 @@ ac_add_options --disable-unified-compilation ac_add_options --target=arm-linux-androideabi ac_add_options --with-arch=armv6 -export JAVA_HOME=/tools/jdk6 export MOZILLA_OFFICIAL=1 export MOZ_TELEMETRY_REPORTING=1 export MOZ_PKG_SPECIAL=armv6 diff --git a/mobile/android/config/mozconfigs/android-armv6/l10n-nightly b/mobile/android/config/mozconfigs/android-armv6/l10n-nightly index 69e73ba3710..184f6feeff5 100644 --- a/mobile/android/config/mozconfigs/android-armv6/l10n-nightly +++ b/mobile/android/config/mozconfigs/android-armv6/l10n-nightly @@ -16,7 +16,6 @@ ac_add_options --with-arch=armv6 ac_add_options --enable-updater ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} -export JAVA_HOME=/tools/jdk6 export MOZILLA_OFFICIAL=1 export MOZ_PKG_SPECIAL=armv6 export MOZ_DISABLE_GECKOVIEW=1 diff --git a/mobile/android/config/mozconfigs/android-armv6/l10n-release b/mobile/android/config/mozconfigs/android-armv6/l10n-release index fb4fc7cb614..12b9d8d3511 100644 --- a/mobile/android/config/mozconfigs/android-armv6/l10n-release +++ b/mobile/android/config/mozconfigs/android-armv6/l10n-release @@ -13,7 +13,6 @@ ac_add_options --with-arch=armv6 ac_add_options --enable-updater ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} -export JAVA_HOME=/tools/jdk6 export MOZILLA_OFFICIAL=1 export MOZ_PKG_SPECIAL=armv6 export MOZ_DISABLE_GECKOVIEW=1 diff --git a/mobile/android/config/mozconfigs/android-armv6/nightly b/mobile/android/config/mozconfigs/android-armv6/nightly index 3d1306c06dc..6362e2a1885 100644 --- a/mobile/android/config/mozconfigs/android-armv6/nightly +++ b/mobile/android/config/mozconfigs/android-armv6/nightly @@ -7,7 +7,6 @@ export MOZ_PKG_SPECIAL=armv6 ac_add_options --with-branding=mobile/android/branding/nightly -export JAVA_HOME=/tools/jdk6 export MOZILLA_OFFICIAL=1 export MOZ_TELEMETRY_REPORTING=1 diff --git a/mobile/android/config/mozconfigs/android-armv6/release b/mobile/android/config/mozconfigs/android-armv6/release index d15353ef93e..ae813650fe2 100644 --- a/mobile/android/config/mozconfigs/android-armv6/release +++ b/mobile/android/config/mozconfigs/android-armv6/release @@ -9,7 +9,6 @@ ac_add_options --with-branding=mobile/android/branding/beta ac_add_options --enable-updater -export JAVA_HOME=/tools/jdk6 export MOZILLA_OFFICIAL=1 export MOZ_TELEMETRY_REPORTING=1 diff --git a/mobile/android/config/mozconfigs/android-x86/debug b/mobile/android/config/mozconfigs/android-x86/debug index c5ecbb0e88c..1e9450bd9be 100644 --- a/mobile/android/config/mozconfigs/android-x86/debug +++ b/mobile/android/config/mozconfigs/android-x86/debug @@ -7,7 +7,6 @@ ac_add_options --disable-unified-compilation # Android ac_add_options --target=i386-linux-android -export JAVA_HOME=/tools/jdk6 export MOZILLA_OFFICIAL=1 export MOZ_TELEMETRY_REPORTING=1 diff --git a/mobile/android/config/mozconfigs/android-x86/l10n-nightly b/mobile/android/config/mozconfigs/android-x86/l10n-nightly index bc151722f8d..181128ef57f 100644 --- a/mobile/android/config/mozconfigs/android-x86/l10n-nightly +++ b/mobile/android/config/mozconfigs/android-x86/l10n-nightly @@ -15,7 +15,6 @@ ac_add_options --target=i386-linux-android ac_add_options --enable-updater ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} -export JAVA_HOME=/tools/jdk6 export MOZILLA_OFFICIAL=1 export MOZ_DISABLE_GECKOVIEW=1 diff --git a/mobile/android/config/mozconfigs/android-x86/l10n-release b/mobile/android/config/mozconfigs/android-x86/l10n-release index 42602e0835d..3eca447fcb2 100644 --- a/mobile/android/config/mozconfigs/android-x86/l10n-release +++ b/mobile/android/config/mozconfigs/android-x86/l10n-release @@ -12,7 +12,6 @@ ac_add_options --target=i386-linux-android ac_add_options --enable-updater ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} -export JAVA_HOME=/tools/jdk6 export MOZILLA_OFFICIAL=1 export MOZ_DISABLE_GECKOVIEW=1 diff --git a/mobile/android/config/mozconfigs/android-x86/nightly b/mobile/android/config/mozconfigs/android-x86/nightly index 20e7f239950..c0f2407814d 100644 --- a/mobile/android/config/mozconfigs/android-x86/nightly +++ b/mobile/android/config/mozconfigs/android-x86/nightly @@ -11,7 +11,6 @@ ac_add_options --with-branding=mobile/android/branding/nightly # This is useful for profiling with eideticker. See bug 788680 STRIP_FLAGS="--strip-debug" -export JAVA_HOME=/tools/jdk6 export MOZILLA_OFFICIAL=1 export MOZ_TELEMETRY_REPORTING=1 diff --git a/mobile/android/config/mozconfigs/android-x86/release b/mobile/android/config/mozconfigs/android-x86/release index 0160f7cd28e..d8250742d82 100644 --- a/mobile/android/config/mozconfigs/android-x86/release +++ b/mobile/android/config/mozconfigs/android-x86/release @@ -7,7 +7,6 @@ ac_add_options --enable-updater ac_add_options --with-branding=mobile/android/branding/beta -export JAVA_HOME=/tools/jdk6 export MOZILLA_OFFICIAL=1 export MOZ_TELEMETRY_REPORTING=1 diff --git a/mobile/android/config/mozconfigs/android/debug b/mobile/android/config/mozconfigs/android/debug index 66844a8d1c2..8313acd1804 100644 --- a/mobile/android/config/mozconfigs/android/debug +++ b/mobile/android/config/mozconfigs/android/debug @@ -6,7 +6,6 @@ ac_add_options --enable-debug # Android ac_add_options --target=arm-linux-androideabi -export JAVA_HOME=/tools/jdk6 export MOZILLA_OFFICIAL=1 export MOZ_TELEMETRY_REPORTING=1 diff --git a/mobile/android/config/mozconfigs/android/l10n-nightly b/mobile/android/config/mozconfigs/android/l10n-nightly index f935bbb84ff..d75e3712902 100644 --- a/mobile/android/config/mozconfigs/android/l10n-nightly +++ b/mobile/android/config/mozconfigs/android/l10n-nightly @@ -17,7 +17,6 @@ ac_add_options --with-system-zlib ac_add_options --enable-updater ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} -export JAVA_HOME=/tools/jdk6 export MOZILLA_OFFICIAL=1 export MOZ_DISABLE_GECKOVIEW=1 diff --git a/mobile/android/config/mozconfigs/android/l10n-release b/mobile/android/config/mozconfigs/android/l10n-release index 50a98b3a9e2..b64d8b6763e 100644 --- a/mobile/android/config/mozconfigs/android/l10n-release +++ b/mobile/android/config/mozconfigs/android/l10n-release @@ -14,7 +14,6 @@ ac_add_options --with-system-zlib ac_add_options --enable-updater ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} -export JAVA_HOME=/tools/jdk6 export MOZILLA_OFFICIAL=1 export MOZ_DISABLE_GECKOVIEW=1 diff --git a/mobile/android/config/mozconfigs/android/nightly b/mobile/android/config/mozconfigs/android/nightly index 561355bbe35..1bc2b08cfbe 100644 --- a/mobile/android/config/mozconfigs/android/nightly +++ b/mobile/android/config/mozconfigs/android/nightly @@ -12,7 +12,6 @@ ac_add_options --with-branding=mobile/android/branding/nightly # This is useful for profiling with eideticker. See bug 788680 STRIP_FLAGS="--strip-debug" -export JAVA_HOME=/tools/jdk6 export MOZILLA_OFFICIAL=1 export MOZ_TELEMETRY_REPORTING=1 diff --git a/mobile/android/config/mozconfigs/android/release b/mobile/android/config/mozconfigs/android/release index e452df9d5eb..4c51ddd79d6 100644 --- a/mobile/android/config/mozconfigs/android/release +++ b/mobile/android/config/mozconfigs/android/release @@ -7,7 +7,6 @@ ac_add_options --enable-updater ac_add_options --with-branding=mobile/android/branding/beta -export JAVA_HOME=/tools/jdk6 export MOZILLA_OFFICIAL=1 export MOZ_TELEMETRY_REPORTING=1 diff --git a/mobile/android/config/mozconfigs/common b/mobile/android/config/mozconfigs/common index 6012317c76a..e4587de7443 100644 --- a/mobile/android/config/mozconfigs/common +++ b/mobile/android/config/mozconfigs/common @@ -47,3 +47,7 @@ HOST_CXX="/tools/gcc-4.7.2-0moz1/bin/g++" # Avoid dependency on libstdc++ 4.7 ac_add_options --enable-stdcxx-compat + +mk_add_options "export ANT_HOME=$topsrcdir/apache-ant" + +mk_add_options "export PATH=$topsrcdir/gcc/bin:$topsrcdir/apache-ant/bin:$PATH" diff --git a/mobile/android/config/tooltool-manifests/android-armv6/releng.manifest b/mobile/android/config/tooltool-manifests/android-armv6/releng.manifest index 21aba6d4898..619b39e4530 100644 --- a/mobile/android/config/tooltool-manifests/android-armv6/releng.manifest +++ b/mobile/android/config/tooltool-manifests/android-armv6/releng.manifest @@ -12,15 +12,21 @@ "filename": "android-sdk.tar.xz" }, { -"size": 217, -"digest": "5aaec0a91da377fb1bf86ac2a28a2adea3d3f7736b71c0fb2249ae8ca0ff66731311f89c9e933f0944e8e5771a0c14d6a3055f181721f52a0cd5397f175bcb14", +"size": 335, +"digest": "2f0e2f345b39789e24de032a156c53d1895c69b525d661c57d208fd528e22694841213a06f52e70fac17b9161e107c581260d95dacda0a5710b90d57668dc895", "algorithm": "sha512", "filename": "setup.sh" }, { -"size": 150816, -"digest": "af25ecf03b65795d21f011939984b130db167a4efc4f306700f373854f9d7ae664662cb7812c3d737eace7f3735324daa6eb540b5e42f90189b0d9a8dd5f4c9f", +"size": 160232, +"digest": "8656c3fc2daa66839ec81a0edbd9759040a83c7a41c3e472d7f90508b80eefd008b87305dc8549b4ff6098dc33fe17fedc9b4eb76cf5307d5f22dae925c033db", "algorithm": "sha512", "filename": "sccache.tar.xz" +}, +{ +"size": 7920445, +"digest": "e28b7a12fbbef02ad742958df8dd356ea2adb8ef79e95cd8eb8dbc953eb4cc11888969dac7d636187fd3ace9c63d9a6bc3d7795021c1d811a843e413fe5e52c9", +"algorithm": "sha512", +"filename": "apache-ant-bin.tar.bz2" } ] diff --git a/mobile/android/config/tooltool-manifests/android-x86/releng.manifest b/mobile/android/config/tooltool-manifests/android-x86/releng.manifest index 6ccc1bf1787..7877a55aca5 100644 --- a/mobile/android/config/tooltool-manifests/android-x86/releng.manifest +++ b/mobile/android/config/tooltool-manifests/android-x86/releng.manifest @@ -12,15 +12,21 @@ "filename": "android-sdk.tar.xz" }, { -"size": 217, -"digest": "5aaec0a91da377fb1bf86ac2a28a2adea3d3f7736b71c0fb2249ae8ca0ff66731311f89c9e933f0944e8e5771a0c14d6a3055f181721f52a0cd5397f175bcb14", +"size": 335, +"digest": "2f0e2f345b39789e24de032a156c53d1895c69b525d661c57d208fd528e22694841213a06f52e70fac17b9161e107c581260d95dacda0a5710b90d57668dc895", "algorithm": "sha512", "filename": "setup.sh" }, { -"size": 150816, -"digest": "af25ecf03b65795d21f011939984b130db167a4efc4f306700f373854f9d7ae664662cb7812c3d737eace7f3735324daa6eb540b5e42f90189b0d9a8dd5f4c9f", +"size": 160232, +"digest": "8656c3fc2daa66839ec81a0edbd9759040a83c7a41c3e472d7f90508b80eefd008b87305dc8549b4ff6098dc33fe17fedc9b4eb76cf5307d5f22dae925c033db", "algorithm": "sha512", "filename": "sccache.tar.xz" +}, +{ +"size": 7920445, +"digest": "e28b7a12fbbef02ad742958df8dd356ea2adb8ef79e95cd8eb8dbc953eb4cc11888969dac7d636187fd3ace9c63d9a6bc3d7795021c1d811a843e413fe5e52c9", +"algorithm": "sha512", +"filename": "apache-ant-bin.tar.bz2" } ] diff --git a/mobile/android/config/tooltool-manifests/android/releng.manifest b/mobile/android/config/tooltool-manifests/android/releng.manifest index 21aba6d4898..619b39e4530 100644 --- a/mobile/android/config/tooltool-manifests/android/releng.manifest +++ b/mobile/android/config/tooltool-manifests/android/releng.manifest @@ -12,15 +12,21 @@ "filename": "android-sdk.tar.xz" }, { -"size": 217, -"digest": "5aaec0a91da377fb1bf86ac2a28a2adea3d3f7736b71c0fb2249ae8ca0ff66731311f89c9e933f0944e8e5771a0c14d6a3055f181721f52a0cd5397f175bcb14", +"size": 335, +"digest": "2f0e2f345b39789e24de032a156c53d1895c69b525d661c57d208fd528e22694841213a06f52e70fac17b9161e107c581260d95dacda0a5710b90d57668dc895", "algorithm": "sha512", "filename": "setup.sh" }, { -"size": 150816, -"digest": "af25ecf03b65795d21f011939984b130db167a4efc4f306700f373854f9d7ae664662cb7812c3d737eace7f3735324daa6eb540b5e42f90189b0d9a8dd5f4c9f", +"size": 160232, +"digest": "8656c3fc2daa66839ec81a0edbd9759040a83c7a41c3e472d7f90508b80eefd008b87305dc8549b4ff6098dc33fe17fedc9b4eb76cf5307d5f22dae925c033db", "algorithm": "sha512", "filename": "sccache.tar.xz" +}, +{ +"size": 7920445, +"digest": "e28b7a12fbbef02ad742958df8dd356ea2adb8ef79e95cd8eb8dbc953eb4cc11888969dac7d636187fd3ace9c63d9a6bc3d7795021c1d811a843e413fe5e52c9", +"algorithm": "sha512", +"filename": "apache-ant-bin.tar.bz2" } ] diff --git a/modules/libjar/nsJAR.cpp b/modules/libjar/nsJAR.cpp index 73686445231..05ea619a342 100644 --- a/modules/libjar/nsJAR.cpp +++ b/modules/libjar/nsJAR.cpp @@ -95,7 +95,7 @@ NS_IMPL_QUERY_INTERFACE1(nsJAR, nsIZipReader) NS_IMPL_ADDREF(nsJAR) // Custom Release method works with nsZipReaderCache... -nsrefcnt nsJAR::Release(void) +MozExternalRefCountType nsJAR::Release(void) { nsrefcnt count; NS_PRECONDITION(0 != mRefCnt, "dup release"); diff --git a/modules/libjar/nsZipArchive.h b/modules/libjar/nsZipArchive.h index 2ef7819bd2c..bb2de4373fc 100644 --- a/modules/libjar/nsZipArchive.h +++ b/modules/libjar/nsZipArchive.h @@ -196,8 +196,8 @@ public: /* * Refcounting */ - NS_METHOD_(nsrefcnt) AddRef(void); - NS_METHOD_(nsrefcnt) Release(void); + NS_METHOD_(MozExternalRefCountType) AddRef(void); + NS_METHOD_(MozExternalRefCountType) Release(void); private: //--- private members --- @@ -378,8 +378,8 @@ public: static nsresult Init(nsZipArchive *zip, const char *entry, nsZipHandle **ret); - NS_METHOD_(nsrefcnt) AddRef(void); - NS_METHOD_(nsrefcnt) Release(void); + NS_METHOD_(MozExternalRefCountType) AddRef(void); + NS_METHOD_(MozExternalRefCountType) Release(void); int64_t SizeOfMapping(); diff --git a/mozglue/build/Nuwa.cpp b/mozglue/build/Nuwa.cpp index 06ece36f1d0..974ca4c2b54 100644 --- a/mozglue/build/Nuwa.cpp +++ b/mozglue/build/Nuwa.cpp @@ -143,7 +143,7 @@ TLSInfoList; */ #ifndef NUWA_STACK_SIZE #ifndef PAGE_SIZE -#warning "Hard-coding page size to 4096 byte +#warning "Hard-coding page size to 4096 byte" #define PAGE_SIZE 4096ul #endif #define PAGE_ALIGN_MASK (~(PAGE_SIZE-1)) diff --git a/netwerk/base/public/nsIDivertableChannel.idl b/netwerk/base/public/nsIDivertableChannel.idl index 0e92d081f98..ca1d9665383 100644 --- a/netwerk/base/public/nsIDivertableChannel.idl +++ b/netwerk/base/public/nsIDivertableChannel.idl @@ -7,7 +7,6 @@ #include "nsISupports.idl" %{C++ -//#include "mozilla/net/ChannelDiverterChild.h" namespace mozilla { namespace net { class ChannelDiverterChild; diff --git a/netwerk/base/public/nsIParentChannel.idl b/netwerk/base/public/nsIParentChannel.idl index d795a72e496..c7bb16a96aa 100644 --- a/netwerk/base/public/nsIParentChannel.idl +++ b/netwerk/base/public/nsIParentChannel.idl @@ -6,13 +6,28 @@ interface nsITabParent; +%{C++ +namespace mozilla { +namespace net { +class HttpChannelParentListener; +} +} +%} + +[ptr] native HttpChannelParentListener(mozilla::net::HttpChannelParentListener); + /** * Implemented by chrome side of IPC protocols. */ -[scriptable, uuid(723188c3-fff8-4d27-b657-a256e7209be0)] +[scriptable, uuid(8bf3aa90-ec5d-4977-bd03-197274befc78)] interface nsIParentChannel : nsIStreamListener { + /** + * Called to set the HttpChannelParentListener object (optional). + */ + [noscript] void setParentListener(in HttpChannelParentListener listener); + /** * Called to invoke deletion of the IPC protocol. */ diff --git a/netwerk/base/public/nsIParentRedirectingChannel.idl b/netwerk/base/public/nsIParentRedirectingChannel.idl index 8ba40f188d4..df37a0131b0 100644 --- a/netwerk/base/public/nsIParentRedirectingChannel.idl +++ b/netwerk/base/public/nsIParentRedirectingChannel.idl @@ -12,7 +12,7 @@ interface nsIAsyncVerifyRedirectCallback; * Implemented by chrome side of IPC protocols that support redirect responses. */ -[scriptable, uuid(cb7edc1c-096f-44de-957c-cb93de1545f6)] +[scriptable, uuid(3ed1d288-5324-46ee-8a98-33ac37d1080b)] interface nsIParentRedirectingChannel : nsIParentChannel { /** diff --git a/netwerk/base/src/nsProtocolProxyService.cpp b/netwerk/base/src/nsProtocolProxyService.cpp index 0cd4603acb3..6ebd33fba40 100644 --- a/netwerk/base/src/nsProtocolProxyService.cpp +++ b/netwerk/base/src/nsProtocolProxyService.cpp @@ -1008,7 +1008,7 @@ private: nsCString mPACURL; bool mCompleted; }; -NS_IMPL_ISUPPORTS1(nsAsyncBridgeRequest, nsPACManCallback) +NS_IMPL_ISUPPORTS0(nsAsyncBridgeRequest) // nsIProtocolProxyService2 NS_IMETHODIMP diff --git a/netwerk/base/src/nsSocketTransport2.cpp b/netwerk/base/src/nsSocketTransport2.cpp index 2386d76095f..58431d43772 100644 --- a/netwerk/base/src/nsSocketTransport2.cpp +++ b/netwerk/base/src/nsSocketTransport2.cpp @@ -310,14 +310,14 @@ NS_IMPL_QUERY_INTERFACE2(nsSocketInputStream, nsIInputStream, nsIAsyncInputStream) -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) nsSocketInputStream::AddRef() { ++mReaderRefCnt; return mTransport->AddRef(); } -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) nsSocketInputStream::Release() { if (--mReaderRefCnt == 0) @@ -573,14 +573,14 @@ NS_IMPL_QUERY_INTERFACE2(nsSocketOutputStream, nsIOutputStream, nsIAsyncOutputStream) -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) nsSocketOutputStream::AddRef() { ++mWriterRefCnt; return mTransport->AddRef(); } -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) nsSocketOutputStream::Release() { if (--mWriterRefCnt == 0) diff --git a/netwerk/cache/nsCacheEntryDescriptor.cpp b/netwerk/cache/nsCacheEntryDescriptor.cpp index 11822d3faf8..5d2c947827b 100644 --- a/netwerk/cache/nsCacheEntryDescriptor.cpp +++ b/netwerk/cache/nsCacheEntryDescriptor.cpp @@ -655,7 +655,7 @@ nsCacheEntryDescriptor::VisitMetaData(nsICacheMetaDataVisitor * visitor) ******************************************************************************/ NS_IMPL_ADDREF(nsCacheEntryDescriptor::nsInputStreamWrapper) -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) nsCacheEntryDescriptor::nsInputStreamWrapper::Release() { // Holding a reference to descriptor ensures that cache service won't go @@ -847,7 +847,7 @@ nsInputStreamWrapper::IsNonBlocking(bool *result) ******************************************************************************/ NS_IMPL_ADDREF(nsCacheEntryDescriptor::nsDecompressInputStreamWrapper) -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) nsCacheEntryDescriptor::nsDecompressInputStreamWrapper::Release() { // Holding a reference to descriptor ensures that cache service won't go @@ -1037,7 +1037,7 @@ nsDecompressInputStreamWrapper::EndZstream() ******************************************************************************/ NS_IMPL_ADDREF(nsCacheEntryDescriptor::nsOutputStreamWrapper) -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) nsCacheEntryDescriptor::nsOutputStreamWrapper::Release() { // Holding a reference to descriptor ensures that cache service won't go @@ -1267,7 +1267,7 @@ nsOutputStreamWrapper::IsNonBlocking(bool *result) ******************************************************************************/ NS_IMPL_ADDREF(nsCacheEntryDescriptor::nsCompressOutputStreamWrapper) -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) nsCacheEntryDescriptor::nsCompressOutputStreamWrapper::Release() { // Holding a reference to descriptor ensures that cache service won't go diff --git a/netwerk/cache2/CacheFileChunk.cpp b/netwerk/cache2/CacheFileChunk.cpp index 5fd9f7dcff2..f449625d90a 100644 --- a/netwerk/cache2/CacheFileChunk.cpp +++ b/netwerk/cache2/CacheFileChunk.cpp @@ -98,7 +98,7 @@ private: NS_IMPL_ADDREF(CacheFileChunk) -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) CacheFileChunk::Release() { NS_PRECONDITION(0 != mRefCnt, "dup release"); diff --git a/netwerk/cache2/CacheFileIOManager.cpp b/netwerk/cache2/CacheFileIOManager.cpp index fb7787abc2d..054e5bf9877 100644 --- a/netwerk/cache2/CacheFileIOManager.cpp +++ b/netwerk/cache2/CacheFileIOManager.cpp @@ -58,7 +58,7 @@ CacheFileHandle::DispatchRelease() return false; } - nsRefPtr > event = + nsRefPtr > event = NS_NewNonOwningRunnableMethod(this, &CacheFileHandle::Release); nsresult rv = ioTarget->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL); if (NS_FAILED(rv)) { @@ -69,7 +69,7 @@ CacheFileHandle::DispatchRelease() } NS_IMPL_ADDREF(CacheFileHandle) -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) CacheFileHandle::Release() { nsrefcnt count = mRefCnt - 1; @@ -1753,11 +1753,13 @@ CacheFileIOManager::CloseHandleInternal(CacheFileHandle *aHandle) CacheIndex::RemoveEntry(aHandle->Hash()); } - // Remove the handle from hashtable - if (aHandle->IsSpecialFile()) { - mSpecialHandles.RemoveElement(aHandle); - } else if (!mShuttingDown) { // Don't touch after shutdown - mHandles.RemoveHandle(aHandle); + // Don't remove handles after shutdown + if (!mShuttingDown) { + if (aHandle->IsSpecialFile()) { + mSpecialHandles.RemoveElement(aHandle); + } else { + mHandles.RemoveHandle(aHandle); + } } return NS_OK; @@ -3293,7 +3295,7 @@ class SizeOfHandlesRunnable : public nsRunnable public: SizeOfHandlesRunnable(mozilla::MallocSizeOf mallocSizeOf, CacheFileHandles const &handles, - nsTArray > const &specialHandles) + nsTArray const &specialHandles) : mMonitor("SizeOfHandlesRunnable.mMonitor") , mMallocSizeOf(mallocSizeOf) , mHandles(handles) @@ -3338,7 +3340,7 @@ private: mozilla::Monitor mMonitor; mozilla::MallocSizeOf mMallocSizeOf; CacheFileHandles const &mHandles; - nsTArray > const &mSpecialHandles; + nsTArray const &mSpecialHandles; size_t mSize; }; diff --git a/netwerk/cache2/CacheFileIOManager.h b/netwerk/cache2/CacheFileIOManager.h index 508685eb1af..ee6d273d018 100644 --- a/netwerk/cache2/CacheFileIOManager.h +++ b/netwerk/cache2/CacheFileIOManager.h @@ -357,7 +357,7 @@ private: bool mTreeCreated; CacheFileHandles mHandles; nsTArray mHandlesByLastUsed; - nsTArray > mSpecialHandles; + nsTArray mSpecialHandles; nsTArray > mScheduledMetadataWrites; nsCOMPtr mMetadataWritesTimer; bool mOverLimitEvicting; diff --git a/netwerk/cache2/CacheFileInputStream.cpp b/netwerk/cache2/CacheFileInputStream.cpp index c29f9746c4e..6f264a27263 100644 --- a/netwerk/cache2/CacheFileInputStream.cpp +++ b/netwerk/cache2/CacheFileInputStream.cpp @@ -14,7 +14,7 @@ namespace mozilla { namespace net { NS_IMPL_ADDREF(CacheFileInputStream) -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) CacheFileInputStream::Release() { NS_PRECONDITION(0 != mRefCnt, "dup release"); diff --git a/netwerk/cache2/CacheFileOutputStream.cpp b/netwerk/cache2/CacheFileOutputStream.cpp index ddf062c3aa1..0951aaae20e 100644 --- a/netwerk/cache2/CacheFileOutputStream.cpp +++ b/netwerk/cache2/CacheFileOutputStream.cpp @@ -16,7 +16,7 @@ namespace mozilla { namespace net { NS_IMPL_ADDREF(CacheFileOutputStream) -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) CacheFileOutputStream::Release() { NS_PRECONDITION(0 != mRefCnt, "dup release"); diff --git a/netwerk/cache2/CacheIndex.cpp b/netwerk/cache2/CacheIndex.cpp index 5f17eb8ddac..886456e5e15 100644 --- a/netwerk/cache2/CacheIndex.cpp +++ b/netwerk/cache2/CacheIndex.cpp @@ -24,8 +24,7 @@ #define kMinDumpInterval 20000 // in milliseconds #define kMaxBufSize 16384 #define kIndexVersion 0x00000001 -#define kBuildIndexStartDelay 10000 // in milliseconds -#define kUpdateIndexStartDelay 10000 // in milliseconds +#define kUpdateIndexStartDelay 50000 // in milliseconds const char kIndexName[] = "index"; const char kTempIndexName[] = "index.tmp"; @@ -2651,6 +2650,9 @@ CacheIndex::StartUpdatingIndex(bool aRebuild) uint32_t elapsed = (TimeStamp::NowLoRes() - mStartTime).ToMilliseconds(); if (elapsed < kUpdateIndexStartDelay) { + LOG(("CacheIndex::StartUpdatingIndex() - %u ms elapsed since startup, " + "scheduling timer to fire in %u ms.", elapsed, + kUpdateIndexStartDelay - elapsed)); rv = ScheduleUpdateTimer(kUpdateIndexStartDelay - elapsed); if (NS_SUCCEEDED(rv)) { return; @@ -2658,6 +2660,9 @@ CacheIndex::StartUpdatingIndex(bool aRebuild) LOG(("CacheIndex::StartUpdatingIndex() - ScheduleUpdateTimer() failed. " "Starting update immediately.")); + } else { + LOG(("CacheIndex::StartUpdatingIndex() - %u ms elapsed since startup, " + "starting update now.", elapsed)); } nsRefPtr ioThread = CacheFileIOManager::IOThread(); diff --git a/netwerk/ipc/ChannelEventQueue.cpp b/netwerk/ipc/ChannelEventQueue.cpp index eac17c18210..8f236da2eec 100644 --- a/netwerk/ipc/ChannelEventQueue.cpp +++ b/netwerk/ipc/ChannelEventQueue.cpp @@ -54,9 +54,27 @@ ChannelEventQueue::Resume() if (!--mSuspendCount) { nsRefPtr > event = NS_NewRunnableMethod(this, &ChannelEventQueue::CompleteResume); - NS_DispatchToCurrentThread(event); + if (mTargetThread) { + mTargetThread->Dispatch(event, NS_DISPATCH_NORMAL); + } else { + MOZ_RELEASE_ASSERT(NS_IsMainThread()); + NS_DispatchToCurrentThread(event); + } } } +nsresult +ChannelEventQueue::RetargetDeliveryTo(nsIEventTarget* aTargetThread) +{ + MOZ_RELEASE_ASSERT(NS_IsMainThread()); + MOZ_RELEASE_ASSERT(!mTargetThread); + MOZ_RELEASE_ASSERT(aTargetThread); + + mTargetThread = do_QueryInterface(aTargetThread); + MOZ_RELEASE_ASSERT(mTargetThread); + + return NS_OK; +} + } } diff --git a/netwerk/ipc/ChannelEventQueue.h b/netwerk/ipc/ChannelEventQueue.h index 87c58afe44b..dc4cff0ad01 100644 --- a/netwerk/ipc/ChannelEventQueue.h +++ b/netwerk/ipc/ChannelEventQueue.h @@ -12,6 +12,8 @@ #include class nsISupports; +class nsIEventTarget; +class nsIThread; namespace mozilla { namespace net { @@ -71,6 +73,9 @@ class ChannelEventQueue // dispatched in a new event on the current thread. void Resume(); + // Retargets delivery of events to the target thread specified. + nsresult RetargetDeliveryTo(nsIEventTarget* aTargetThread); + private: inline void MaybeFlushQueue(); void FlushQueue(); @@ -86,6 +91,9 @@ class ChannelEventQueue // Keep ptr to avoid refcount cycle: only grab ref during flushing. nsISupports *mOwner; + // Target thread for delivery of events. + nsCOMPtr mTargetThread; + friend class AutoEventEnqueuer; }; diff --git a/netwerk/protocol/file/moz.build b/netwerk/protocol/file/moz.build index 6bc25858773..1249307ab9e 100644 --- a/netwerk/protocol/file/moz.build +++ b/netwerk/protocol/file/moz.build @@ -24,5 +24,4 @@ FINAL_LIBRARY = 'necko' LOCAL_INCLUDES += [ '../../base/src', - '/xpcom/ds', ] diff --git a/netwerk/protocol/ftp/FTPChannelParent.cpp b/netwerk/protocol/ftp/FTPChannelParent.cpp index 160e19aa67a..ce8a396fbc9 100644 --- a/netwerk/protocol/ftp/FTPChannelParent.cpp +++ b/netwerk/protocol/ftp/FTPChannelParent.cpp @@ -376,6 +376,13 @@ FTPChannelParent::OnDataAvailable(nsIRequest* aRequest, // FTPChannelParent::nsIParentChannel //----------------------------------------------------------------------------- +NS_IMETHODIMP +FTPChannelParent::SetParentListener(HttpChannelParentListener* aListener) +{ + // Do not need ptr to HttpChannelParentListener. + return NS_OK; +} + NS_IMETHODIMP FTPChannelParent::Delete() { diff --git a/netwerk/protocol/ftp/moz.build b/netwerk/protocol/ftp/moz.build index ad457be67b2..fd0ffaad765 100644 --- a/netwerk/protocol/ftp/moz.build +++ b/netwerk/protocol/ftp/moz.build @@ -42,5 +42,4 @@ FINAL_LIBRARY = 'necko' LOCAL_INCLUDES += [ '../../base/src', - '/xpcom/ds', ] diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp index 90d9f067bee..22c6fd65e5b 100644 --- a/netwerk/protocol/http/HttpChannelChild.cpp +++ b/netwerk/protocol/http/HttpChannelChild.cpp @@ -66,7 +66,7 @@ HttpChannelChild::~HttpChannelChild() // Override nsHashPropertyBag's AddRef: we don't need thread-safe refcnt NS_IMPL_ADDREF(HttpChannelChild) -NS_IMETHODIMP_(nsrefcnt) HttpChannelChild::Release() +NS_IMETHODIMP_(MozExternalRefCountType) HttpChannelChild::Release() { NS_PRECONDITION(0 != mRefCnt, "dup release"); NS_ASSERT_OWNINGTHREAD(HttpChannelChild); diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp index 30423caeac7..a50f33f7709 100644 --- a/netwerk/protocol/http/HttpChannelParent.cpp +++ b/netwerk/protocol/http/HttpChannelParent.cpp @@ -713,6 +713,17 @@ HttpChannelParent::OnStatus(nsIRequest *aRequest, // HttpChannelParent::nsIParentChannel //----------------------------------------------------------------------------- +NS_IMETHODIMP +HttpChannelParent::SetParentListener(HttpChannelParentListener* aListener) +{ + MOZ_ASSERT(aListener); + MOZ_ASSERT(!mParentListener, "SetParentListener should only be called for " + "new HttpChannelParents after a redirect, when " + "mParentListener is null."); + mParentListener = aListener; + return NS_OK; +} + NS_IMETHODIMP HttpChannelParent::Delete() { diff --git a/netwerk/protocol/http/HttpChannelParentListener.cpp b/netwerk/protocol/http/HttpChannelParentListener.cpp index b6b3bb311c4..136b96f5605 100644 --- a/netwerk/protocol/http/HttpChannelParentListener.cpp +++ b/netwerk/protocol/http/HttpChannelParentListener.cpp @@ -219,6 +219,7 @@ HttpChannelParentListener::OnRedirectResult(bool succeeded) parent->Delete(); mNextListener = do_QueryInterface(redirectChannel); MOZ_ASSERT(mNextListener); + redirectChannel->SetParentListener(this); } else if (redirectChannel) { // Delete the redirect target channel: continue using old channel redirectChannel->Delete(); diff --git a/netwerk/protocol/http/moz.build b/netwerk/protocol/http/moz.build index 8e835815a5e..06b2f244c99 100644 --- a/netwerk/protocol/http/moz.build +++ b/netwerk/protocol/http/moz.build @@ -106,5 +106,4 @@ LOCAL_INCLUDES += [ '../../base/src', '/content/base/src', '/dom/events', - '/xpcom/ds', ] diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.cpp b/netwerk/protocol/http/nsHttpConnectionMgr.cpp index a7b1ae0f10a..46704d61aa5 100644 --- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp +++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp @@ -346,8 +346,8 @@ public: // Added manually so we can use nsRefPtr without inheriting from // nsISupports - NS_IMETHOD_(nsrefcnt) AddRef(void); - NS_IMETHOD_(nsrefcnt) Release(void); + NS_IMETHOD_(MozExternalRefCountType) AddRef(void); + NS_IMETHOD_(MozExternalRefCountType) Release(void); public: // intentional! nsRefPtr mTrans; diff --git a/netwerk/protocol/http/nsHttpTransaction.cpp b/netwerk/protocol/http/nsHttpTransaction.cpp index 155f487bcd9..aa2b5ed41f6 100644 --- a/netwerk/protocol/http/nsHttpTransaction.cpp +++ b/netwerk/protocol/http/nsHttpTransaction.cpp @@ -1841,7 +1841,7 @@ nsHttpTransaction::CancelPacing(nsresult reason) NS_IMPL_ADDREF(nsHttpTransaction) -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) nsHttpTransaction::Release() { nsrefcnt count; diff --git a/netwerk/protocol/rtsp/controller/RtspController.cpp b/netwerk/protocol/rtsp/controller/RtspController.cpp index d8acf5d446a..bee1b05e673 100644 --- a/netwerk/protocol/rtsp/controller/RtspController.cpp +++ b/netwerk/protocol/rtsp/controller/RtspController.cpp @@ -31,8 +31,8 @@ #include "nsProxyRelease.h" #include "nsNetUtil.h" #include "mozilla/Attributes.h" -#include "TimeStamp.h" #include "mozilla/Telemetry.h" +#include "mozilla/TimeStamp.h" #include "prlog.h" #include "plbase64.h" @@ -188,7 +188,9 @@ RtspController::AsyncOpen(nsIStreamingProtocolListener *aListener) return NS_ERROR_NOT_INITIALIZED; } - mListener = aListener; + // Use main thread pointer, but allow access off main thread. + mListener = + new nsMainThreadPtrHolder(aListener, false); if (!mURI) { LOG(("RtspController::AsyncOpen() illegal URI")); @@ -330,6 +332,9 @@ RtspController::OnDisconnected(uint8_t index, if (mListener) { nsRefPtr task = new SendOnDisconnectedTask(mListener, index, reason); + // Break the cycle reference between the Listener (RtspControllerParent) and + // us. + mListener = nullptr; return NS_DispatchToMainThread(task); } return NS_ERROR_NOT_AVAILABLE; diff --git a/netwerk/protocol/rtsp/controller/RtspController.h b/netwerk/protocol/rtsp/controller/RtspController.h index 62635d2bce0..d932dcf7385 100644 --- a/netwerk/protocol/rtsp/controller/RtspController.h +++ b/netwerk/protocol/rtsp/controller/RtspController.h @@ -37,7 +37,7 @@ private: // RTSP URL refer to a stream or an aggregate of streams. nsCOMPtr mURI; // The nsIStreamingProtocolListener implementation. - nsCOMPtr mListener; + nsMainThreadPtrHandle mListener; // ASCII encoded URL spec. nsCString mSpec; // Indicate the connection state between the diff --git a/netwerk/protocol/rtsp/controller/RtspControllerChild.cpp b/netwerk/protocol/rtsp/controller/RtspControllerChild.cpp index e6f9332d24d..170bb2b2b1c 100644 --- a/netwerk/protocol/rtsp/controller/RtspControllerChild.cpp +++ b/netwerk/protocol/rtsp/controller/RtspControllerChild.cpp @@ -55,8 +55,12 @@ NS_INTERFACE_MAP_BEGIN(RtspControllerChild) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStreamingProtocolController) NS_INTERFACE_MAP_END +//----------------------------------------------------------------------------- +// RtspControllerChild methods +//----------------------------------------------------------------------------- RtspControllerChild::RtspControllerChild(nsIChannel *channel) : mIPCOpen(false) + , mIPCAllowed(false) , mChannel(channel) , mTotalTracks(0) , mSuspendCount(0) @@ -74,6 +78,33 @@ RtspControllerChild::~RtspControllerChild() LOG(("RtspControllerChild::~RtspControllerChild()")); } +bool +RtspControllerChild::OKToSendIPC() +{ + MOZ_ASSERT(NS_IsMainThread()); + if (mIPCOpen == false) { + return false; + } + return mIPCAllowed; +} + +void +RtspControllerChild::AllowIPC() +{ + MOZ_ASSERT(NS_IsMainThread()); + mIPCAllowed = true; +} + +void +RtspControllerChild::DisallowIPC() +{ + MOZ_ASSERT(NS_IsMainThread()); + mIPCAllowed = false; +} + +//----------------------------------------------------------------------------- +// RtspControllerChild::PRtspControllerChild +//----------------------------------------------------------------------------- bool RtspControllerChild::RecvOnMediaDataAvailable( const uint8_t& index, @@ -138,6 +169,7 @@ RtspControllerChild::RecvOnDisconnected( const uint8_t& index, const nsresult& reason) { + DisallowIPC(); LOG(("RtspControllerChild::RecvOnDisconnected for track %d reason = 0x%x", index, reason)); if (mListener) { mListener->OnDisconnected(index, reason); @@ -148,6 +180,7 @@ RtspControllerChild::RecvOnDisconnected( bool RtspControllerChild::RecvAsyncOpenFailed(const nsresult& reason) { + DisallowIPC(); LOG(("RtspControllerChild::RecvAsyncOpenFailed reason = 0x%x", reason)); if (mListener) { mListener->OnDisconnected(0, NS_ERROR_CONNECTION_REFUSED); @@ -161,6 +194,7 @@ RtspControllerChild::AddIPDLReference() NS_ABORT_IF_FALSE(!mIPCOpen, "Attempt to retain more than one IPDL reference"); mIPCOpen = true; + AllowIPC(); AddRef(); } @@ -169,6 +203,7 @@ RtspControllerChild::ReleaseIPDLReference() { NS_ABORT_IF_FALSE(mIPCOpen, "Attempt to release nonexistent IPDL reference"); mIPCOpen = false; + DisallowIPC(); Release(); } @@ -219,22 +254,31 @@ public: NS_IMETHOD Run() { MOZ_ASSERT(NS_IsMainThread()); + if (mController->OKToSendIPC() == false) { + // Don't send any more IPC events; no guarantee that parent objects are + // still alive. + return NS_ERROR_FAILURE; + } + bool rv = true; if (mEvent == SendPlayEvent) { - mController->SendPlay(); + rv = mController->SendPlay(); } else if (mEvent == SendPauseEvent) { - mController->SendPause(); + rv = mController->SendPause(); } else if (mEvent == SendSeekEvent) { - mController->SendSeek(mSeekTime); + rv = mController->SendSeek(mSeekTime); } else if (mEvent == SendResumeEvent) { - mController->SendResume(); + rv = mController->SendResume(); } else if (mEvent == SendSuspendEvent) { - mController->SendSuspend(); + rv = mController->SendSuspend(); } else if (mEvent == SendStopEvent) { - mController->SendStop(); + rv = mController->SendStop(); } else { LOG(("RtspControllerChild::SendIPCEvent")); } + if (!rv) { + return NS_ERROR_FAILURE; + } return NS_OK; } private: @@ -243,15 +287,18 @@ private: uint64_t mSeekTime; }; +//----------------------------------------------------------------------------- +// RtspControllerChild::nsIStreamingProtocolController +//----------------------------------------------------------------------------- NS_IMETHODIMP RtspControllerChild::Play(void) { LOG(("RtspControllerChild::Play()")); - NS_ENSURE_TRUE(mIPCOpen, NS_ERROR_FAILURE); if (NS_IsMainThread()) { - if (!SendPlay()) + if (!OKToSendIPC() || !SendPlay()) { return NS_ERROR_FAILURE; + } } else { nsresult rv = NS_DispatchToMainThread( new SendIPCEvent(this, SendPlayEvent)); @@ -265,11 +312,11 @@ NS_IMETHODIMP RtspControllerChild::Pause(void) { LOG(("RtspControllerChild::Pause()")); - NS_ENSURE_TRUE(mIPCOpen, NS_ERROR_FAILURE); if (NS_IsMainThread()) { - if (!SendPause()) + if (!OKToSendIPC() || !SendPause()) { return NS_ERROR_FAILURE; + } } else { nsresult rv = NS_DispatchToMainThread( new SendIPCEvent(this, SendPauseEvent)); @@ -283,13 +330,13 @@ NS_IMETHODIMP RtspControllerChild::Resume(void) { LOG(("RtspControllerChild::Resume()")); - NS_ENSURE_TRUE(mIPCOpen, NS_ERROR_FAILURE); NS_ENSURE_TRUE(mSuspendCount > 0, NS_ERROR_UNEXPECTED); if (!--mSuspendCount) { if (NS_IsMainThread()) { - if (!SendResume()) + if (!OKToSendIPC() || !SendResume()) { return NS_ERROR_FAILURE; + } } else { nsresult rv = NS_DispatchToMainThread( new SendIPCEvent(this, SendResumeEvent)); @@ -304,12 +351,12 @@ NS_IMETHODIMP RtspControllerChild::Suspend(void) { LOG(("RtspControllerChild::Suspend()")); - NS_ENSURE_TRUE(mIPCOpen, NS_ERROR_FAILURE); if (!mSuspendCount++) { if (NS_IsMainThread()) { - if (!SendSuspend()) + if (!OKToSendIPC() || !SendSuspend()) { return NS_ERROR_FAILURE; + } } else { nsresult rv = NS_DispatchToMainThread( new SendIPCEvent(this, SendSuspendEvent)); @@ -324,11 +371,11 @@ NS_IMETHODIMP RtspControllerChild::Seek(uint64_t seekTimeUs) { LOG(("RtspControllerChild::Seek() %llu", seekTimeUs)); - NS_ENSURE_TRUE(mIPCOpen, NS_ERROR_FAILURE); if (NS_IsMainThread()) { - if (!SendSeek(seekTimeUs)) + if (!OKToSendIPC() || !SendSeek(seekTimeUs)) { return NS_ERROR_FAILURE; + } } else { nsresult rv = NS_DispatchToMainThread( new SendIPCEvent(this, SendSeekEvent, seekTimeUs)); @@ -342,11 +389,12 @@ NS_IMETHODIMP RtspControllerChild::Stop() { LOG(("RtspControllerChild::Stop()")); - NS_ENSURE_TRUE(mIPCOpen, NS_ERROR_FAILURE); if (NS_IsMainThread()) { - if (!SendStop()) + if (!OKToSendIPC() || !SendStop()) { return NS_ERROR_FAILURE; + } + DisallowIPC(); } else { nsresult rv = NS_DispatchToMainThread( new SendIPCEvent(this, SendStopEvent)); @@ -368,6 +416,9 @@ RtspControllerChild::GetTotalTracks(uint8_t *aTracks) return NS_OK; } +//----------------------------------------------------------------------------- +// RtspControllerChild::nsIStreamingProtocolListener +//----------------------------------------------------------------------------- NS_IMETHODIMP RtspControllerChild::OnMediaDataAvailable(uint8_t index, const nsACString & data, @@ -396,6 +447,9 @@ RtspControllerChild::OnDisconnected(uint8_t index, return NS_ERROR_NOT_IMPLEMENTED; } +//----------------------------------------------------------------------------- +// RtspControllerChild::nsIStreamingProtocoController +//----------------------------------------------------------------------------- NS_IMETHODIMP RtspControllerChild::Init(nsIURI *aURI) { @@ -454,7 +508,7 @@ RtspControllerChild::AsyncOpen(nsIStreamingProtocolListener *aListener) } SerializeURI(uri, uriParams); - if (!mIPCOpen || !SendAsyncOpen(uriParams)) { + if (!OKToSendIPC() || !SendAsyncOpen(uriParams)) { return NS_ERROR_FAILURE; } return NS_OK; diff --git a/netwerk/protocol/rtsp/controller/RtspControllerChild.h b/netwerk/protocol/rtsp/controller/RtspControllerChild.h index 8f191a6a73f..113469dc9ea 100644 --- a/netwerk/protocol/rtsp/controller/RtspControllerChild.h +++ b/netwerk/protocol/rtsp/controller/RtspControllerChild.h @@ -47,9 +47,15 @@ class RtspControllerChild : public nsIStreamingProtocolController void ReleaseIPDLReference(); void AddMetaData(already_AddRefed&& meta); int GetMetaDataLength(); + bool OKToSendIPC(); + void AllowIPC(); + void DisallowIPC(); private: bool mIPCOpen; + // The intention of this variable is just to avoid any IPC message to be sent + // when this flag is set as false. Nothing more. + bool mIPCAllowed; // Dummy channel used to aid MediaResource creation in HTMLMediaElement. nsCOMPtr mChannel; // The nsIStreamingProtocolListener implementation. diff --git a/netwerk/protocol/rtsp/controller/RtspControllerParent.cpp b/netwerk/protocol/rtsp/controller/RtspControllerParent.cpp index 982f50ae1c5..241194606ad 100644 --- a/netwerk/protocol/rtsp/controller/RtspControllerParent.cpp +++ b/netwerk/protocol/rtsp/controller/RtspControllerParent.cpp @@ -57,8 +57,10 @@ RtspControllerParent::ActorDestroy(ActorDestroyReason why) mIPCOpen = false; NS_ENSURE_TRUE_VOID(mController); - mController->Stop(); - mController = nullptr; + if (mController) { + mController->Stop(); + mController = nullptr; + } } bool @@ -260,6 +262,9 @@ RtspControllerParent::OnDisconnected(uint8_t index, if (!mIPCOpen || !SendOnDisconnected(index, reason)) { return NS_ERROR_FAILURE; } + if (mController) { + mController = nullptr; + } return NS_OK; } diff --git a/netwerk/protocol/rtsp/moz.build b/netwerk/protocol/rtsp/moz.build index e722f41d2d1..af2946a8e20 100644 --- a/netwerk/protocol/rtsp/moz.build +++ b/netwerk/protocol/rtsp/moz.build @@ -56,7 +56,6 @@ LOCAL_INCLUDES += [ '../../base/src', '/content/base/src', '/dom/events', - '/xpcom/ds', 'controller', 'rtsp', ] diff --git a/netwerk/protocol/rtsp/rtsp/RTSPSource.cpp b/netwerk/protocol/rtsp/rtsp/RTSPSource.cpp index e25fd6b3232..2e745db1a2d 100644 --- a/netwerk/protocol/rtsp/rtsp/RTSPSource.cpp +++ b/netwerk/protocol/rtsp/rtsp/RTSPSource.cpp @@ -52,7 +52,9 @@ RTSPSource::RTSPSource( { CHECK(aListener != NULL); - mListener = aListener; + // Use main thread pointer, but allow access off main thread. + mListener = + new nsMainThreadPtrHolder(aListener, false); mPrintCount = 0; } @@ -542,7 +544,7 @@ void RTSPSource::onConnected(bool isSeekable) meta->SetSampleRate(int32Value); } else { CHECK(format->findInt32(kKeyWidth, &int32Value)); - meta->SetWidth(int32Value); + meta->SetWidth(int32Value); CHECK(format->findInt32(kKeyHeight, &int32Value)); meta->SetHeight(int32Value); @@ -578,8 +580,8 @@ void RTSPSource::onDisconnected(const sp &msg) { CHECK(msg->findInt32("result", &err)); if ((mLooper != NULL) && (mHandler != NULL)) { - mLooper->unregisterHandler(mHandler->id()); - mHandler.clear(); + mLooper->unregisterHandler(mHandler->id()); + mHandler.clear(); } mState = DISCONNECTED; @@ -589,11 +591,10 @@ void RTSPSource::onDisconnected(const sp &msg) { finishDisconnectIfPossible(); } if (mListener) { - if (err == OK) { - mListener->OnDisconnected(0, NS_OK); - } else { - mListener->OnDisconnected(0, NS_ERROR_NET_TIMEOUT); - } + nsresult reason = (err == OK) ? NS_OK : NS_ERROR_NET_TIMEOUT; + mListener->OnDisconnected(0, reason); + // Break the cycle reference between RtspController and us. + mListener = nullptr; } mAudioTrack = NULL; mVideoTrack = NULL; diff --git a/netwerk/protocol/rtsp/rtsp/RTSPSource.h b/netwerk/protocol/rtsp/rtsp/RTSPSource.h index cf36960f5c7..46e734081be 100644 --- a/netwerk/protocol/rtsp/rtsp/RTSPSource.h +++ b/netwerk/protocol/rtsp/rtsp/RTSPSource.h @@ -25,6 +25,7 @@ #include "nsCOMPtr.h" #include "nsString.h" #include "nsIStreamingProtocolController.h" +#include "nsProxyRelease.h" namespace android { @@ -140,7 +141,7 @@ private: void onTrackDataAvailable(size_t trackIndex); - nsCOMPtr mListener; + nsMainThreadPtrHandle mListener; int mPrintCount; DISALLOW_EVIL_CONSTRUCTORS(RTSPSource); diff --git a/netwerk/protocol/websocket/BaseWebSocketChannel.cpp b/netwerk/protocol/websocket/BaseWebSocketChannel.cpp index 11d930e245c..0b68ee6d383 100644 --- a/netwerk/protocol/websocket/BaseWebSocketChannel.cpp +++ b/netwerk/protocol/websocket/BaseWebSocketChannel.cpp @@ -6,6 +6,7 @@ #include "WebSocketLog.h" #include "BaseWebSocketChannel.h" +#include "MainThreadUtils.h" #include "nsILoadGroup.h" #include "nsIInterfaceRequestor.h" #include "nsAutoPtr.h" @@ -242,5 +243,22 @@ BaseWebSocketChannel::AllowPort(int32_t port, const char *scheme, return NS_OK; } +//----------------------------------------------------------------------------- +// BaseWebSocketChannel::nsIThreadRetargetableRequest +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +BaseWebSocketChannel::RetargetDeliveryTo(nsIEventTarget* aTargetThread) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aTargetThread); + MOZ_ASSERT(!mTargetThread, "Delivery target should be set once, before AsyncOpen"); + MOZ_ASSERT(!mWasOpened, "Should not be called after AsyncOpen!"); + + mTargetThread = do_QueryInterface(aTargetThread); + MOZ_ASSERT(mTargetThread); + return NS_OK; +} + } // namespace net } // namespace mozilla diff --git a/netwerk/protocol/websocket/BaseWebSocketChannel.h b/netwerk/protocol/websocket/BaseWebSocketChannel.h index 2e3611a0dd7..df7e1a12d5b 100644 --- a/netwerk/protocol/websocket/BaseWebSocketChannel.h +++ b/netwerk/protocol/websocket/BaseWebSocketChannel.h @@ -10,6 +10,8 @@ #include "nsIWebSocketChannel.h" #include "nsIWebSocketListener.h" #include "nsIProtocolHandler.h" +#include "nsIThread.h" +#include "nsIThreadRetargetableRequest.h" #include "nsCOMPtr.h" #include "nsString.h" @@ -20,16 +22,18 @@ const static int32_t kDefaultWSPort = 80; const static int32_t kDefaultWSSPort = 443; class BaseWebSocketChannel : public nsIWebSocketChannel, - public nsIProtocolHandler + public nsIProtocolHandler, + public nsIThreadRetargetableRequest { public: BaseWebSocketChannel(); NS_DECL_NSIPROTOCOLHANDLER + NS_DECL_NSITHREADRETARGETABLEREQUEST NS_IMETHOD QueryInterface(const nsIID & uuid, void **result) = 0; - NS_IMETHOD_(nsrefcnt ) AddRef(void) = 0; - NS_IMETHOD_(nsrefcnt ) Release(void) = 0; + NS_IMETHOD_(MozExternalRefCountType ) AddRef(void) = 0; + NS_IMETHOD_(MozExternalRefCountType ) Release(void) = 0; // Partial implementation of nsIWebSocketChannel // @@ -54,6 +58,7 @@ class BaseWebSocketChannel : public nsIWebSocketChannel, nsCOMPtr mContext; nsCOMPtr mCallbacks; nsCOMPtr mLoadGroup; + nsCOMPtr mTargetThread; nsCString mProtocol; nsCString mOrigin; diff --git a/netwerk/protocol/websocket/WebSocketChannel.cpp b/netwerk/protocol/websocket/WebSocketChannel.cpp index 114164db0cb..752ed0bc03e 100644 --- a/netwerk/protocol/websocket/WebSocketChannel.cpp +++ b/netwerk/protocol/websocket/WebSocketChannel.cpp @@ -34,6 +34,7 @@ #include "nsIProtocolHandler.h" #include "nsIRandomGenerator.h" #include "nsISocketTransport.h" +#include "nsThreadUtils.h" #include "nsAutoPtr.h" #include "nsNetCID.h" @@ -45,6 +46,7 @@ #include "nsAlgorithm.h" #include "nsProxyRelease.h" #include "nsNetUtil.h" +#include "mozilla/StaticMutex.h" #include "mozilla/Telemetry.h" #include "mozilla/TimeStamp.h" @@ -69,7 +71,7 @@ using namespace mozilla; namespace mozilla { namespace net { -NS_IMPL_ISUPPORTS12(WebSocketChannel, +NS_IMPL_ISUPPORTS13(WebSocketChannel, nsIWebSocketChannel, nsIHttpUpgradeListener, nsIRequestObserver, @@ -81,7 +83,8 @@ NS_IMPL_ISUPPORTS12(WebSocketChannel, nsIDNSListener, nsIProtocolProxyCallback, nsIInterfaceRequestor, - nsIChannelEventSink) + nsIChannelEventSink, + nsIThreadRetargetableRequest) // We implement RFC 6455, which uses Sec-WebSocket-Version: 13 on the wire. #define SEC_WEBSOCKET_VERSION "13" @@ -317,81 +320,88 @@ private: class nsWSAdmissionManager { public: - nsWSAdmissionManager() : mSessionCount(0) + static void Init() { - MOZ_COUNT_CTOR(nsWSAdmissionManager); + StaticMutexAutoLock lock(sLock); + if (!sManager) { + sManager = new nsWSAdmissionManager(); + } } - class nsOpenConn + static void Shutdown() { - public: - nsOpenConn(nsCString &addr, WebSocketChannel *channel) - : mAddress(addr), mChannel(channel) { MOZ_COUNT_CTOR(nsOpenConn); } - ~nsOpenConn() { MOZ_COUNT_DTOR(nsOpenConn); } - - nsCString mAddress; - WebSocketChannel *mChannel; - }; - - ~nsWSAdmissionManager() - { - MOZ_COUNT_DTOR(nsWSAdmissionManager); - for (uint32_t i = 0; i < mQueue.Length(); i++) - delete mQueue[i]; + StaticMutexAutoLock lock(sLock); + delete sManager; + sManager = nullptr; } // Determine if we will open connection immediately (returns true), or // delay/queue the connection (returns false) - void ConditionallyConnect(WebSocketChannel *ws) + static void ConditionallyConnect(WebSocketChannel *ws) { NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread"); NS_ABORT_IF_FALSE(ws->mConnecting == NOT_CONNECTING, "opening state"); + StaticMutexAutoLock lock(sLock); + if (!sManager) { + return; + } + // If there is already another WS channel connecting to this IP address, // defer BeginOpen and mark as waiting in queue. - bool found = (IndexOf(ws->mAddress) >= 0); + bool found = (sManager->IndexOf(ws->mAddress) >= 0); // Always add ourselves to queue, even if we'll connect immediately nsOpenConn *newdata = new nsOpenConn(ws->mAddress, ws); - mQueue.AppendElement(newdata); + sManager->mQueue.AppendElement(newdata); if (found) { ws->mConnecting = CONNECTING_QUEUED; } else { - mFailures.DelayOrBegin(ws); + sManager->mFailures.DelayOrBegin(ws); } } - void OnConnected(WebSocketChannel *aChannel) + static void OnConnected(WebSocketChannel *aChannel) { NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread"); NS_ABORT_IF_FALSE(aChannel->mConnecting == CONNECTING_IN_PROGRESS, "Channel completed connect, but not connecting?"); + StaticMutexAutoLock lock(sLock); + if (!sManager) { + return; + } + aChannel->mConnecting = NOT_CONNECTING; // Remove from queue - RemoveFromQueue(aChannel); + sManager->RemoveFromQueue(aChannel); // Connection succeeded, so stop keeping track of any previous failures - mFailures.Remove(aChannel->mAddress, aChannel->mPort); + sManager->mFailures.Remove(aChannel->mAddress, aChannel->mPort); // Check for queued connections to same host. // Note: still need to check for failures, since next websocket with same // host may have different port - ConnectNext(aChannel->mAddress); + sManager->ConnectNext(aChannel->mAddress); } // Called every time a websocket channel ends its session (including going away // w/o ever successfully creating a connection) - void OnStopSession(WebSocketChannel *aChannel, nsresult aReason) + static void OnStopSession(WebSocketChannel *aChannel, nsresult aReason) { NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread"); + StaticMutexAutoLock lock(sLock); + if (!sManager) { + return; + } + if (NS_FAILED(aReason)) { // Have we seen this failure before? - FailDelay *knownFailure = mFailures.Lookup(aChannel->mAddress, - aChannel->mPort); + FailDelay *knownFailure = sManager->mFailures.Lookup(aChannel->mAddress, + aChannel->mPort); if (knownFailure) { if (aReason == NS_ERROR_NOT_CONNECTED) { // Don't count close() before connection as a network error @@ -406,7 +416,7 @@ public: // new connection failure: record it. LOG(("WebSocket: connection to %s, %d failed: [this=%p]", aChannel->mAddress.get(), (int)aChannel->mPort, aChannel)); - mFailures.Add(aChannel->mAddress, aChannel->mPort); + sManager->mFailures.Add(aChannel->mAddress, aChannel->mPort); } } @@ -417,16 +427,67 @@ public: aChannel->mScriptCloseCode == CLOSE_GOING_AWAY, "websocket closed while connecting w/o failing?"); - RemoveFromQueue(aChannel); + sManager->RemoveFromQueue(aChannel); bool wasNotQueued = (aChannel->mConnecting != CONNECTING_QUEUED); aChannel->mConnecting = NOT_CONNECTING; if (wasNotQueued) { - ConnectNext(aChannel->mAddress); + sManager->ConnectNext(aChannel->mAddress); } } } + static void IncrementSessionCount() + { + StaticMutexAutoLock lock(sLock); + if (!sManager) { + return; + } + sManager->mSessionCount++; + } + + static void DecrementSessionCount() + { + StaticMutexAutoLock lock(sLock); + if (!sManager) { + return; + } + sManager->mSessionCount--; + } + + static void GetSessionCount(int32_t &aSessionCount) + { + StaticMutexAutoLock lock(sLock); + if (!sManager) { + return; + } + aSessionCount = sManager->mSessionCount; + } + +private: + nsWSAdmissionManager() : mSessionCount(0) + { + MOZ_COUNT_CTOR(nsWSAdmissionManager); + } + + ~nsWSAdmissionManager() + { + MOZ_COUNT_DTOR(nsWSAdmissionManager); + for (uint32_t i = 0; i < mQueue.Length(); i++) + delete mQueue[i]; + } + + class nsOpenConn + { + public: + nsOpenConn(nsCString &addr, WebSocketChannel *channel) + : mAddress(addr), mChannel(channel) { MOZ_COUNT_CTOR(nsOpenConn); } + ~nsOpenConn() { MOZ_COUNT_DTOR(nsOpenConn); } + + nsCString mAddress; + WebSocketChannel *mChannel; + }; + void ConnectNext(nsCString &hostName) { int32_t index = IndexOf(hostName); @@ -441,23 +502,6 @@ public: } } - void IncrementSessionCount() - { - mSessionCount++; - } - - void DecrementSessionCount() - { - mSessionCount--; - } - - int32_t SessionCount() - { - return mSessionCount; - } - -private: - void RemoveFromQueue(WebSocketChannel *aChannel) { int32_t index = IndexOf(aChannel); @@ -499,9 +543,13 @@ private: nsTArray mQueue; FailDelayManager mFailures; + + static nsWSAdmissionManager *sManager; + static StaticMutex sLock; }; -static nsWSAdmissionManager *sWebSocketAdmissions = nullptr; +nsWSAdmissionManager *nsWSAdmissionManager::sManager; +StaticMutex nsWSAdmissionManager::sLock; //----------------------------------------------------------------------------- // CallOnMessageAvailable @@ -521,6 +569,8 @@ public: NS_IMETHOD Run() { + MOZ_ASSERT(NS_GetCurrentThread() == mChannel->mTargetThread); + if (mLen < 0) mChannel->mListener->OnMessageAvailable(mChannel->mContext, mData); else @@ -553,9 +603,9 @@ public: NS_IMETHOD Run() { - NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread"); + MOZ_ASSERT(NS_GetCurrentThread() == mChannel->mTargetThread); - sWebSocketAdmissions->OnStopSession(mChannel, mReason); + nsWSAdmissionManager::OnStopSession(mChannel, mReason); if (mChannel->mListener) { mChannel->mListener->OnStop(mChannel->mContext, mReason); @@ -591,6 +641,8 @@ public: NS_IMETHOD Run() { + MOZ_ASSERT(NS_GetCurrentThread() == mChannel->mTargetThread); + mChannel->mListener->OnServerClose(mChannel->mContext, mCode, mReason); return NS_OK; } @@ -620,6 +672,8 @@ public: NS_IMETHOD Run() { + MOZ_ASSERT(NS_GetCurrentThread() == mChannel->mTargetThread); + LOG(("WebSocketChannel::CallAcknowledge: Size %u\n", mSize)); mChannel->mListener->OnAcknowledge(mChannel->mContext, mSize); return NS_OK; @@ -981,8 +1035,7 @@ WebSocketChannel::WebSocketChannel() : LOG(("WebSocketChannel::WebSocketChannel() %p\n", this)); - if (!sWebSocketAdmissions) - sWebSocketAdmissions = new nsWSAdmissionManager(); + nsWSAdmissionManager::Init(); mFramePtr = mBuffer = static_cast(moz_xmalloc(mBufferSize)); @@ -1053,8 +1106,7 @@ WebSocketChannel::~WebSocketChannel() void WebSocketChannel::Shutdown() { - delete sWebSocketAdmissions; - sWebSocketAdmissions = nullptr; + nsWSAdmissionManager::Shutdown(); } void @@ -1359,15 +1411,11 @@ WebSocketChannel::ProcessInput(uint8_t *buffer, uint32_t count) return NS_ERROR_CANNOT_CONVERT_DATA; } - NS_DispatchToMainThread(new CallOnMessageAvailable(this, utf8Data, -1)); - nsresult rv; + mTargetThread->Dispatch(new CallOnMessageAvailable(this, utf8Data, -1), + NS_DISPATCH_NORMAL); if (mConnectionLogService && !mPrivateBrowsing) { - nsAutoCString host; - rv = mURI->GetHostPort(host); - if (NS_SUCCEEDED(rv)) { - mConnectionLogService->NewMsgReceived(host, mSerial, count); - LOG(("Added new msg received for %s",host.get())); - } + mConnectionLogService->NewMsgReceived(mHost, mSerial, count); + LOG(("Added new msg received for %s", mHost.get())); } } } else if (opcode & kControlFrameMask) { @@ -1411,8 +1459,9 @@ WebSocketChannel::ProcessInput(uint8_t *buffer, uint32_t count) mCloseTimer = nullptr; } if (mListener) { - NS_DispatchToMainThread(new CallOnServerClose(this, mServerCloseCode, - mServerCloseReason)); + mTargetThread->Dispatch(new CallOnServerClose(this, mServerCloseCode, + mServerCloseReason), + NS_DISPATCH_NORMAL); } if (mClientClosed) @@ -1447,17 +1496,13 @@ WebSocketChannel::ProcessInput(uint8_t *buffer, uint32_t count) LOG(("WebSocketChannel:: binary frame received\n")); if (mListener) { nsCString binaryData((const char *)payload, payloadLength); - NS_DispatchToMainThread(new CallOnMessageAvailable(this, binaryData, - payloadLength)); + mTargetThread->Dispatch(new CallOnMessageAvailable(this, binaryData, + payloadLength), + NS_DISPATCH_NORMAL); // To add the header to 'Networking Dashboard' log - nsresult rv; if (mConnectionLogService && !mPrivateBrowsing) { - nsAutoCString host; - rv = mURI->GetHostPort(host); - if (NS_SUCCEEDED(rv)) { - mConnectionLogService->NewMsgReceived(host, mSerial, count); - LOG(("Added new received msg for %s",host.get())); - } + mConnectionLogService->NewMsgReceived(mHost, mSerial, count); + LOG(("Added new received msg for %s", mHost.get())); } } } else if (opcode != kContinuation) { @@ -1870,12 +1915,8 @@ WebSocketChannel::CleanupConnection() mTransport = nullptr; } - nsresult rv; if (mConnectionLogService && !mPrivateBrowsing) { - nsAutoCString host; - rv = mURI->GetHostPort(host); - if (NS_SUCCEEDED(rv)) - mConnectionLogService->RemoveHost(host, mSerial); + mConnectionLogService->RemoveHost(mHost, mSerial); } DecrementSessionCount(); @@ -1940,8 +1981,10 @@ WebSocketChannel::StopSession(nsresult reason) } while (NS_SUCCEEDED(rv) && count > 0 && total < 32000); } - if (!mTCPClosed && mTransport && sWebSocketAdmissions && - sWebSocketAdmissions->SessionCount() < kLingeringCloseThreshold) { + int32_t sessionCount = kLingeringCloseThreshold; + nsWSAdmissionManager::GetSessionCount(sessionCount); + + if (!mTCPClosed && mTransport && sessionCount < kLingeringCloseThreshold) { // 7.1.1 says that the client SHOULD wait for the server to close the TCP // connection. This is so we can reuse port numbers before 2 MSL expires, @@ -1980,7 +2023,8 @@ WebSocketChannel::StopSession(nsresult reason) if (!mCalledOnStop) { mCalledOnStop = 1; - NS_DispatchToMainThread(new CallOnStop(this, reason)); + mTargetThread->Dispatch(new CallOnStop(this, reason), + NS_DISPATCH_NORMAL); } return; @@ -2039,7 +2083,7 @@ void WebSocketChannel::IncrementSessionCount() { if (!mIncrementedSessionCount) { - sWebSocketAdmissions->IncrementSessionCount(); + nsWSAdmissionManager::IncrementSessionCount(); mIncrementedSessionCount = 1; } } @@ -2052,7 +2096,7 @@ WebSocketChannel::DecrementSessionCount() // atomic, and mIncrementedSessionCount/mDecrementedSessionCount are set at // times when they'll never be a race condition for checking/setting them. if (mIncrementedSessionCount && !mDecrementedSessionCount) { - sWebSocketAdmissions->DecrementSessionCount(); + nsWSAdmissionManager::DecrementSessionCount(); mDecrementedSessionCount = 1; } } @@ -2266,7 +2310,7 @@ WebSocketChannel::StartWebsocketData() // We're now done CONNECTING, which means we can now open another, // perhaps parallel, connection to the same host if one // is pending - sWebSocketAdmissions->OnConnected(this); + nsWSAdmissionManager::OnConnected(this); LOG(("WebSocketChannel::StartWebsocketData Notifying Listener %p\n", mListener.get())); @@ -2354,7 +2398,7 @@ WebSocketChannel::OnLookupComplete(nsICancelable *aRequest, } LOG(("WebSocket OnLookupComplete: Proceeding to ConditionallyConnect\n")); - sWebSocketAdmissions->ConditionallyConnect(this); + nsWSAdmissionManager::ConditionallyConnect(this); return NS_OK; } @@ -2511,7 +2555,7 @@ WebSocketChannel::AsyncOnChannelRedirect( // Mark old channel as successfully connected so we'll clear any FailDelay // associated with the old URI. Note: no need to also call OnStopSession: // it's a no-op for successful, already-connected channels. - sWebSocketAdmissions->OnConnected(this); + nsWSAdmissionManager::OnConnected(this); // ApplyForAdmission as if we were starting from fresh... mAddress.Truncate(); @@ -2629,6 +2673,11 @@ WebSocketChannel::AsyncOpen(nsIURI *aURI, nsresult rv; + // Ensure target thread is set. + if (!mTargetThread) { + mTargetThread = do_GetMainThread(); + } + mSocketThread = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); if (NS_FAILED(rv)) { NS_WARNING("unable to continue without socket transport service"); @@ -2688,16 +2737,17 @@ WebSocketChannel::AsyncOpen(nsIURI *aURI, } } - if (sWebSocketAdmissions) + int32_t sessionCount = -1; + nsWSAdmissionManager::GetSessionCount(sessionCount); + if (sessionCount >= 0) { LOG(("WebSocketChannel::AsyncOpen %p sessionCount=%d max=%d\n", this, - sWebSocketAdmissions->SessionCount(), mMaxConcurrentConnections)); + sessionCount, mMaxConcurrentConnections)); + } - if (sWebSocketAdmissions && - sWebSocketAdmissions->SessionCount() >= mMaxConcurrentConnections) - { + if (sessionCount >= mMaxConcurrentConnections) { LOG(("WebSocketChannel: max concurrency %d exceeded (%d)", mMaxConcurrentConnections, - sWebSocketAdmissions->SessionCount())); + sessionCount)); // WebSocket connections are expected to be long lived, so return // an error here instead of queueing @@ -2706,6 +2756,7 @@ WebSocketChannel::AsyncOpen(nsIURI *aURI, mOriginalURI = aURI; mURI = mOriginalURI; + mURI->GetHostPort(mHost); mOrigin = aOrigin; nsCOMPtr localURI; @@ -2756,11 +2807,8 @@ WebSocketChannel::AsyncOpen(nsIURI *aURI, mPrivateBrowsing = NS_UsePrivateBrowsing(localChannel); if (mConnectionLogService && !mPrivateBrowsing) { - nsAutoCString host; - rv = mURI->GetHostPort(host); - if (NS_SUCCEEDED(rv)) { - mConnectionLogService->AddHost(host, mSerial, BaseWebSocketChannel::mEncrypted); - } + mConnectionLogService->AddHost(mHost, mSerial, + BaseWebSocketChannel::mEncrypted); } rv = ApplyForAdmission(); @@ -2844,7 +2892,7 @@ nsresult WebSocketChannel::SendMsgCommon(const nsACString *aMsg, bool aIsBinary, uint32_t aLength, nsIInputStream *aStream) { - NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread"); + NS_ABORT_IF_FALSE(NS_GetCurrentThread() == mTargetThread, "not target thread"); if (mRequestedClose) { LOG(("WebSocketChannel:: Error: send when closed\n")); @@ -2862,14 +2910,9 @@ WebSocketChannel::SendMsgCommon(const nsACString *aMsg, bool aIsBinary, return NS_ERROR_FILE_TOO_BIG; } - nsresult rv; if (mConnectionLogService && !mPrivateBrowsing) { - nsAutoCString host; - rv = mURI->GetHostPort(host); - if (NS_SUCCEEDED(rv)) { - mConnectionLogService->NewMsgSent(host, mSerial, aLength); - LOG(("Added new msg sent for %s",host.get())); - } + mConnectionLogService->NewMsgSent(mHost, mSerial, aLength); + LOG(("Added new msg sent for %s", mHost.get())); } return mSocketThread->Dispatch( @@ -3196,7 +3239,7 @@ WebSocketChannel::OnOutputStreamReady(nsIAsyncOutputStream *aStream) CountSentBytes(amtSent); if (rv == NS_BASE_STREAM_WOULD_BLOCK) { - mSocketOut->AsyncWait(this, 0, 0, nullptr); + mSocketOut->AsyncWait(this, 0, 0, mSocketThread); return NS_OK; } @@ -3217,8 +3260,9 @@ WebSocketChannel::OnOutputStreamReady(nsIAsyncOutputStream *aStream) } else { if (amtSent == toSend) { if (!mStopped) { - NS_DispatchToMainThread(new CallAcknowledge(this, - mCurrentOut->Length())); + mTargetThread->Dispatch(new CallAcknowledge(this, + mCurrentOut->Length()), + NS_DISPATCH_NORMAL); } DeleteCurrentOutGoingMessage(); PrimeNewOutgoingMessage(); diff --git a/netwerk/protocol/websocket/WebSocketChannel.h b/netwerk/protocol/websocket/WebSocketChannel.h index 922571259fe..47f70da2d1a 100644 --- a/netwerk/protocol/websocket/WebSocketChannel.h +++ b/netwerk/protocol/websocket/WebSocketChannel.h @@ -180,6 +180,9 @@ private: nsCString mAddress; int32_t mPort; // WS server port + // Used for off main thread access to the URI string. + nsCString mHost; + nsCOMPtr mTransport; nsCOMPtr mSocketIn; nsCOMPtr mSocketOut; diff --git a/netwerk/protocol/websocket/WebSocketChannelChild.cpp b/netwerk/protocol/websocket/WebSocketChannelChild.cpp index bc80742ca6e..ce993b88b10 100644 --- a/netwerk/protocol/websocket/WebSocketChannelChild.cpp +++ b/netwerk/protocol/websocket/WebSocketChannelChild.cpp @@ -23,7 +23,7 @@ namespace net { NS_IMPL_ADDREF(WebSocketChannelChild) -NS_IMETHODIMP_(nsrefcnt) WebSocketChannelChild::Release() +NS_IMETHODIMP_(MozExternalRefCountType) WebSocketChannelChild::Release() { NS_PRECONDITION(0 != mRefCnt, "dup release"); NS_ASSERT_OWNINGTHREAD(WebSocketChannelChild); @@ -47,11 +47,14 @@ NS_INTERFACE_MAP_BEGIN(WebSocketChannelChild) NS_INTERFACE_MAP_ENTRY(nsIWebSocketChannel) NS_INTERFACE_MAP_ENTRY(nsIProtocolHandler) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebSocketChannel) + NS_INTERFACE_MAP_ENTRY(nsIThreadRetargetableRequest) NS_INTERFACE_MAP_END WebSocketChannelChild::WebSocketChannelChild(bool aSecure) : mIPCOpen(false) { + NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread"); + LOG(("WebSocketChannelChild::WebSocketChannelChild() %p\n", this)); BaseWebSocketChannel::mEncrypted = aSecure; mEventQ = new ChannelEventQueue(static_cast(this)); @@ -78,6 +81,34 @@ WebSocketChannelChild::ReleaseIPDLReference() Release(); } +class WrappedChannelEvent : public nsRunnable +{ +public: + WrappedChannelEvent(ChannelEvent *aChannelEvent) + : mChannelEvent(aChannelEvent) + { + MOZ_RELEASE_ASSERT(aChannelEvent); + } + NS_IMETHOD Run() + { + mChannelEvent->Run(); + return NS_OK; + } +private: + nsAutoPtr mChannelEvent; +}; + +void +WebSocketChannelChild::DispatchToTargetThread(ChannelEvent *aChannelEvent) +{ + MOZ_RELEASE_ASSERT(NS_IsMainThread()); + MOZ_RELEASE_ASSERT(mTargetThread); + MOZ_RELEASE_ASSERT(aChannelEvent); + + mTargetThread->Dispatch(new WrappedChannelEvent(aChannelEvent), + NS_DISPATCH_NORMAL); +} + class StartEvent : public ChannelEvent { public: @@ -105,6 +136,8 @@ WebSocketChannelChild::RecvOnStart(const nsCString& aProtocol, { if (mEventQ->ShouldEnqueue()) { mEventQ->Enqueue(new StartEvent(this, aProtocol, aExtensions)); + } else if (mTargetThread) { + DispatchToTargetThread(new StartEvent(this, aProtocol, aExtensions)); } else { OnStart(aProtocol, aExtensions); } @@ -148,6 +181,8 @@ WebSocketChannelChild::RecvOnStop(const nsresult& aStatusCode) { if (mEventQ->ShouldEnqueue()) { mEventQ->Enqueue(new StopEvent(this, aStatusCode)); + } else if (mTargetThread) { + DispatchToTargetThread(new StopEvent(this, aStatusCode)); } else { OnStop(aStatusCode); } @@ -194,7 +229,9 @@ WebSocketChannelChild::RecvOnMessageAvailable(const nsCString& aMsg) { if (mEventQ->ShouldEnqueue()) { mEventQ->Enqueue(new MessageEvent(this, aMsg, false)); - } else { + } else if (mTargetThread) { + DispatchToTargetThread(new MessageEvent(this, aMsg, false)); + } else { OnMessageAvailable(aMsg); } return true; @@ -215,6 +252,8 @@ WebSocketChannelChild::RecvOnBinaryMessageAvailable(const nsCString& aMsg) { if (mEventQ->ShouldEnqueue()) { mEventQ->Enqueue(new MessageEvent(this, aMsg, true)); + } else if (mTargetThread) { + DispatchToTargetThread(new MessageEvent(this, aMsg, true)); } else { OnBinaryMessageAvailable(aMsg); } @@ -254,6 +293,8 @@ WebSocketChannelChild::RecvOnAcknowledge(const uint32_t& aSize) { if (mEventQ->ShouldEnqueue()) { mEventQ->Enqueue(new AcknowledgeEvent(this, aSize)); + } else if (mTargetThread) { + DispatchToTargetThread(new AcknowledgeEvent(this, aSize)); } else { OnAcknowledge(aSize); } @@ -297,6 +338,8 @@ WebSocketChannelChild::RecvOnServerClose(const uint16_t& aCode, { if (mEventQ->ShouldEnqueue()) { mEventQ->Enqueue(new ServerCloseEvent(this, aCode, aReason)); + } else if (mTargetThread) { + DispatchToTargetThread(new ServerCloseEvent(this, aCode, aReason)); } else { OnServerClose(aCode, aReason); } @@ -322,6 +365,7 @@ WebSocketChannelChild::AsyncOpen(nsIURI *aURI, { LOG(("WebSocketChannelChild::AsyncOpen() %p\n", this)); + NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread"); NS_ABORT_IF_FALSE(aURI && aListener && !mListener, "Invalid state for WebSocketChannelChild::AsyncOpen"); @@ -360,9 +404,38 @@ WebSocketChannelChild::AsyncOpen(nsIURI *aURI, return NS_OK; } +class CloseEvent : public nsRunnable +{ +public: + CloseEvent(WebSocketChannelChild *aChild, + uint16_t aCode, + const nsACString& aReason) + : mChild(aChild) + , mCode(aCode) + , mReason(aReason) + { + MOZ_RELEASE_ASSERT(!NS_IsMainThread()); + MOZ_ASSERT(aChild); + } + NS_IMETHOD Run() + { + MOZ_RELEASE_ASSERT(NS_IsMainThread()); + mChild->Close(mCode, mReason); + return NS_OK; + } +private: + nsRefPtr mChild; + uint16_t mCode; + nsCString mReason; +}; + NS_IMETHODIMP WebSocketChannelChild::Close(uint16_t code, const nsACString & reason) { + if (!NS_IsMainThread()) { + MOZ_RELEASE_ASSERT(NS_GetCurrentThread() == mTargetThread); + return NS_DispatchToMainThread(new CloseEvent(this, code, reason)); + } LOG(("WebSocketChannelChild::Close() %p\n", this)); if (!mIPCOpen || !SendClose(code, nsCString(reason))) @@ -370,9 +443,42 @@ WebSocketChannelChild::Close(uint16_t code, const nsACString & reason) return NS_OK; } +class MsgEvent : public nsRunnable +{ +public: + MsgEvent(WebSocketChannelChild *aChild, + const nsACString &aMsg, + bool aBinaryMsg) + : mChild(aChild) + , mMsg(aMsg) + , mBinaryMsg(aBinaryMsg) + { + MOZ_RELEASE_ASSERT(!NS_IsMainThread()); + MOZ_ASSERT(aChild); + } + NS_IMETHOD Run() + { + MOZ_RELEASE_ASSERT(NS_IsMainThread()); + if (mBinaryMsg) { + mChild->SendBinaryMsg(mMsg); + } else { + mChild->SendMsg(mMsg); + } + return NS_OK; + } +private: + nsRefPtr mChild; + nsCString mMsg; + bool mBinaryMsg; +}; + NS_IMETHODIMP WebSocketChannelChild::SendMsg(const nsACString &aMsg) { + if (!NS_IsMainThread()) { + MOZ_RELEASE_ASSERT(NS_GetCurrentThread() == mTargetThread); + return NS_DispatchToMainThread(new MsgEvent(this, aMsg, false)); + } LOG(("WebSocketChannelChild::SendMsg() %p\n", this)); if (!mIPCOpen || !SendSendMsg(nsCString(aMsg))) @@ -383,6 +489,10 @@ WebSocketChannelChild::SendMsg(const nsACString &aMsg) NS_IMETHODIMP WebSocketChannelChild::SendBinaryMsg(const nsACString &aMsg) { + if (!NS_IsMainThread()) { + MOZ_RELEASE_ASSERT(NS_GetCurrentThread() == mTargetThread); + return NS_DispatchToMainThread(new MsgEvent(this, aMsg, true)); + } LOG(("WebSocketChannelChild::SendBinaryMsg() %p\n", this)); if (!mIPCOpen || !SendSendBinaryMsg(nsCString(aMsg))) @@ -390,19 +500,58 @@ WebSocketChannelChild::SendBinaryMsg(const nsACString &aMsg) return NS_OK; } +class BinaryStreamEvent : public nsRunnable +{ +public: + BinaryStreamEvent(WebSocketChannelChild *aChild, + OptionalInputStreamParams *aStream, + uint32_t aLength) + : mChild(aChild) + , mStream(aStream) + , mLength(aLength) + { + MOZ_RELEASE_ASSERT(!NS_IsMainThread()); + MOZ_ASSERT(aChild); + } + NS_IMETHOD Run() + { + MOZ_ASSERT(NS_IsMainThread()); + mChild->SendBinaryStream(mStream, mLength); + return NS_OK; + } +private: + nsRefPtr mChild; + nsAutoPtr mStream; + uint32_t mLength; +}; + NS_IMETHODIMP WebSocketChannelChild::SendBinaryStream(nsIInputStream *aStream, uint32_t aLength) { - LOG(("WebSocketChannelChild::SendBinaryStream() %p\n", this)); - - OptionalInputStreamParams stream; + OptionalInputStreamParams *stream = new OptionalInputStreamParams(); nsTArray fds; - SerializeInputStream(aStream, stream, fds); + SerializeInputStream(aStream, *stream, fds); MOZ_ASSERT(fds.IsEmpty()); - if (!mIPCOpen || !SendSendBinaryStream(stream, aLength)) + if (!NS_IsMainThread()) { + MOZ_RELEASE_ASSERT(NS_GetCurrentThread() == mTargetThread); + return NS_DispatchToMainThread(new BinaryStreamEvent(this, stream, aLength), + NS_DISPATCH_NORMAL); + } + return SendBinaryStream(stream, aLength); +} + +nsresult +WebSocketChannelChild::SendBinaryStream(OptionalInputStreamParams *aStream, + uint32_t aLength) +{ + LOG(("WebSocketChannelChild::SendBinaryStream() %p\n", this)); + + nsAutoPtr stream(aStream); + + if (!mIPCOpen || !SendSendBinaryStream(*stream, aLength)) return NS_ERROR_UNEXPECTED; return NS_OK; } @@ -414,5 +563,18 @@ WebSocketChannelChild::GetSecurityInfo(nsISupports **aSecurityInfo) return NS_ERROR_NOT_AVAILABLE; } +//----------------------------------------------------------------------------- +// WebSocketChannelChild::nsIThreadRetargetableRequest +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +WebSocketChannelChild::RetargetDeliveryTo(nsIEventTarget* aTargetThread) +{ + nsresult rv = BaseWebSocketChannel::RetargetDeliveryTo(aTargetThread); + MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); + + return mEventQ->RetargetDeliveryTo(aTargetThread); +} + } // namespace net } // namespace mozilla diff --git a/netwerk/protocol/websocket/WebSocketChannelChild.h b/netwerk/protocol/websocket/WebSocketChannelChild.h index c237be8e491..d3ed1324a0d 100644 --- a/netwerk/protocol/websocket/WebSocketChannelChild.h +++ b/netwerk/protocol/websocket/WebSocketChannelChild.h @@ -14,6 +14,7 @@ namespace mozilla { namespace net { +class ChannelEvent; class ChannelEventQueue; class WebSocketChannelChild : public BaseWebSocketChannel, @@ -24,6 +25,7 @@ class WebSocketChannelChild : public BaseWebSocketChannel, ~WebSocketChannelChild(); NS_DECL_ISUPPORTS + NS_DECL_NSITHREADRETARGETABLEREQUEST // nsIWebSocketChannel methods BaseWebSocketChannel didn't implement for us // @@ -33,6 +35,7 @@ class WebSocketChannelChild : public BaseWebSocketChannel, NS_IMETHOD SendMsg(const nsACString &aMsg); NS_IMETHOD SendBinaryMsg(const nsACString &aMsg); NS_IMETHOD SendBinaryStream(nsIInputStream *aStream, uint32_t aLength); + nsresult SendBinaryStream(OptionalInputStreamParams *aStream, uint32_t aLength); NS_IMETHOD GetSecurityInfo(nsISupports **aSecurityInfo); void AddIPDLReference(); @@ -54,6 +57,8 @@ class WebSocketChannelChild : public BaseWebSocketChannel, void OnServerClose(const uint16_t& aCode, const nsCString& aReason); void AsyncOpenFailed(); + void DispatchToTargetThread(ChannelEvent *aChannelEvent); + nsRefPtr mEventQ; bool mIPCOpen; diff --git a/netwerk/protocol/websocket/moz.build b/netwerk/protocol/websocket/moz.build index 6e7ba8008e4..190611e1a5b 100644 --- a/netwerk/protocol/websocket/moz.build +++ b/netwerk/protocol/websocket/moz.build @@ -43,5 +43,4 @@ LOCAL_INCLUDES += [ '../../base/src', '/content/base/src', '/dom/events', - '/xpcom/ds', ] diff --git a/netwerk/sctp/datachannel/moz.build b/netwerk/sctp/datachannel/moz.build index 00af5dcdf93..85bacb1a6dd 100644 --- a/netwerk/sctp/datachannel/moz.build +++ b/netwerk/sctp/datachannel/moz.build @@ -24,7 +24,6 @@ LOCAL_INCLUDES += [ '../src', '/media/mtransport', '/media/webrtc/trunk/third_party/libjingle/source', - '/xpcom/ds', ] DEFINES['INET'] = 1 diff --git a/netwerk/sctp/src/moz.build b/netwerk/sctp/src/moz.build index dda925e6b3b..0292c3ab98c 100644 --- a/netwerk/sctp/src/moz.build +++ b/netwerk/sctp/src/moz.build @@ -50,7 +50,6 @@ LOCAL_INCLUDES += [ '../../base/src', '/content/base/src', '/dom/events', - '/xpcom/ds', ] for var in ('SCTP_SIMPLE_ALLOCATOR', diff --git a/netwerk/streamconv/converters/nsIndexedToHTML.cpp b/netwerk/streamconv/converters/nsIndexedToHTML.cpp index b069c9ea5b1..8f52114665e 100644 --- a/netwerk/streamconv/converters/nsIndexedToHTML.cpp +++ b/netwerk/streamconv/converters/nsIndexedToHTML.cpp @@ -31,7 +31,7 @@ NS_IMPL_ISUPPORTS4(nsIndexedToHTML, nsIRequestObserver, nsIStreamListener) -static void AppendNonAsciiToNCR(const nsAString& in, nsAFlatString& out) +static void AppendNonAsciiToNCR(const nsAString& in, nsCString& out) { nsAString::const_iterator start, end; @@ -43,10 +43,8 @@ static void AppendNonAsciiToNCR(const nsAString& in, nsAFlatString& out) out.Append(*start++); } else { out.AppendLiteral("&#x"); - nsAutoString hex; - hex.AppendInt(*start++, 16); - out.Append(hex); - out.Append((char16_t)';'); + out.AppendInt(*start++, 16); + out.Append(';'); } } } @@ -67,22 +65,6 @@ nsIndexedToHTML::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) { nsresult nsIndexedToHTML::Init(nsIStreamListener* aListener) { - - nsXPIDLString ellipsis; - nsCOMPtr prefs(do_GetService(NS_PREFSERVICE_CONTRACTID)); - if (prefs) { - nsCOMPtr prefVal; - prefs->GetComplexValue("intl.ellipsis", - NS_GET_IID(nsIPrefLocalizedString), - getter_AddRefs(prefVal)); - if (prefVal) - prefVal->ToString(getter_Copies(ellipsis)); - } - if (ellipsis.IsEmpty()) - mEscapedEllipsis.AppendLiteral("…"); - else - mEscapedEllipsis.Adopt(nsEscapeHTML2(ellipsis.get(), ellipsis.Length())); - nsresult rv = NS_OK; mListener = aListener; @@ -120,7 +102,7 @@ nsIndexedToHTML::AsyncConvertData(const char *aFromType, NS_IMETHODIMP nsIndexedToHTML::OnStartRequest(nsIRequest* request, nsISupports *aContext) { - nsString buffer; + nsCString buffer; nsresult rv = DoOnStartRequest(request, aContext, buffer); if (NS_FAILED(rv)) { request->Cancel(rv); @@ -136,13 +118,13 @@ nsIndexedToHTML::OnStartRequest(nsIRequest* request, nsISupports *aContext) { // Push our buffer to the listener. - rv = FormatInputStream(request, aContext, buffer); + rv = SendToListener(request, aContext, buffer); return rv; } nsresult nsIndexedToHTML::DoOnStartRequest(nsIRequest* request, nsISupports *aContext, - nsString& aBuffer) { + nsCString& aBuffer) { nsresult rv; nsCOMPtr channel = do_QueryInterface(request); @@ -168,6 +150,9 @@ nsIndexedToHTML::DoOnStartRequest(nsIRequest* request, nsISupports *aContext, nsCString parentStr; + nsCString buffer; + buffer.AppendLiteral("\n\n\n"); + // XXX - should be using the 300: line from the parser. // We can't guarantee that that comes before any entry, so we'd have to // buffer, and do other painful stuff. @@ -227,8 +212,7 @@ nsIndexedToHTML::DoOnStartRequest(nsIRequest* request, nsISupports *aContext, } // Directory index will be always encoded in UTF-8 if this is file url - rv = mParser->SetEncoding("UTF-8"); - NS_ENSURE_SUCCESS(rv, rv); + buffer.AppendLiteral("\n"); } else if (NS_SUCCEEDED(uri->SchemeIs("jar", &isScheme)) && isScheme) { nsAutoCString path; @@ -263,23 +247,11 @@ nsIndexedToHTML::DoOnStartRequest(nsIRequest* request, nsISupports *aContext, } } - nsString buffer; - buffer.AppendLiteral("\n" - "\n\n" - "\n" - "