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/base/android-services.mozbuild b/mobile/android/base/android-services.mozbuild index d87c70a0489..61aa84ce746 100644 --- a/mobile/android/base/android-services.mozbuild +++ b/mobile/android/base/android-services.mozbuild @@ -581,6 +581,7 @@ sync_java_files = [ 'fxa/login/TokensAndKeysState.java', 'fxa/receivers/FxAccountDeletedReceiver.java', 'fxa/receivers/FxAccountDeletedService.java', + 'fxa/receivers/FxAccountUpgradeReceiver.java', 'fxa/sync/FxAccountGlobalSession.java', 'fxa/sync/FxAccountNotificationManager.java', 'fxa/sync/FxAccountSchedulePolicy.java', diff --git a/mobile/android/base/db/AbstractPerProfileDatabaseProvider.java b/mobile/android/base/db/AbstractPerProfileDatabaseProvider.java new file mode 100644 index 00000000000..832192765fb --- /dev/null +++ b/mobile/android/base/db/AbstractPerProfileDatabaseProvider.java @@ -0,0 +1,79 @@ +/* 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/. */ + +package org.mozilla.gecko.db; + +import org.mozilla.gecko.mozglue.RobocopTarget; + +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.net.Uri; + +/** + * The base class for ContentProviders that wish to use a different DB + * for each profile. + * + * This class has logic shared between ordinary per-profile CPs and + * those that wish to share DB connections between CPs. + */ +public abstract class AbstractPerProfileDatabaseProvider extends AbstractTransactionalProvider { + + /** + * Extend this to provide access to your own map of shared databases. This + * is a method so that your subclass doesn't collide with others! + */ + protected abstract PerProfileDatabases getDatabases(); + + /* + * Fetches a readable database based on the profile indicated in the + * passed URI. If the URI does not contain a profile param, the default profile + * is used. + * + * @param uri content URI optionally indicating the profile of the user + * @return instance of a readable SQLiteDatabase + */ + @Override + protected SQLiteDatabase getReadableDatabase(Uri uri) { + String profile = null; + if (uri != null) { + profile = uri.getQueryParameter(BrowserContract.PARAM_PROFILE); + } + + return getDatabases().getDatabaseHelperForProfile(profile, isTest(uri)).getReadableDatabase(); + } + + /* + * Fetches a writable database based on the profile indicated in the + * passed URI. If the URI does not contain a profile param, the default profile + * is used + * + * @param uri content URI optionally indicating the profile of the user + * @return instance of a writable SQLiteDatabase + */ + @Override + protected SQLiteDatabase getWritableDatabase(Uri uri) { + String profile = null; + if (uri != null) { + profile = uri.getQueryParameter(BrowserContract.PARAM_PROFILE); + } + + return getDatabases().getDatabaseHelperForProfile(profile, isTest(uri)).getWritableDatabase(); + } + + protected SQLiteDatabase getWritableDatabaseForProfile(String profile, boolean isTest) { + return getDatabases().getDatabaseHelperForProfile(profile, isTest).getWritableDatabase(); + } + + /** + * This method should ONLY be used for testing purposes. + * + * @param uri content URI optionally indicating the profile of the user + * @return instance of a writable SQLiteDatabase + */ + @Override + @RobocopTarget + public SQLiteDatabase getWritableDatabaseForTesting(Uri uri) { + return getWritableDatabase(uri); + } +} diff --git a/mobile/android/base/db/TransactionalProvider.java b/mobile/android/base/db/AbstractTransactionalProvider.java similarity index 55% rename from mobile/android/base/db/TransactionalProvider.java rename to mobile/android/base/db/AbstractTransactionalProvider.java index 536953ab544..6f4a1dba4bd 100644 --- a/mobile/android/base/db/TransactionalProvider.java +++ b/mobile/android/base/db/AbstractTransactionalProvider.java @@ -1,199 +1,66 @@ /* 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/. */ + * 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/. */ package org.mozilla.gecko.db; -import org.mozilla.gecko.db.BrowserContract.CommonColumns; -import org.mozilla.gecko.db.BrowserContract.SyncColumns; -import org.mozilla.gecko.db.PerProfileDatabases.DatabaseHelperFactory; -import org.mozilla.gecko.mozglue.RobocopTarget; - import android.content.ContentProvider; -import android.content.ContentUris; import android.content.ContentValues; -import android.content.Context; import android.database.Cursor; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; import android.net.Uri; import android.os.Build; import android.text.TextUtils; import android.util.Log; -/* - * Abstract class containing methods needed to make a SQLite-based content provider with a - * database helper of type T. Abstract methods insertInTransaction, deleteInTransaction and - * updateInTransaction all called within a DB transaction so failed modifications can be rolled-back. +/** + * This abstract class exists to capture some of the transaction-handling + * commonalities in Fennec's DB layer. + * + * In particular, this abstracts DB access, batching, and a particular + * transaction approach. + * + * That approach is: subclasses implement the abstract methods + * {@link #insertInTransaction(android.net.Uri, android.content.ContentValues)}, + * {@link #deleteInTransaction(android.net.Uri, String, String[])}, and + * {@link #updateInTransaction(android.net.Uri, android.content.ContentValues, String, String[])}. + * + * These are all called expecting a transaction to be established, so failed + * modifications can be rolled-back, and work batched. + * + * If no transaction is established, that's not a problem. Transaction nesting + * can be avoided by using {@link #beginWrite(SQLiteDatabase)}. + * + * The decision of when to begin a transaction is left to the subclasses, + * primarily to avoid the pattern of a transaction being begun, a read occurring, + * and then a write being necessary. This lock upgrade can result in SQLITE_BUSY, + * which we don't handle well. Better to avoid starting a transaction too soon! + * + * You are probably interested in some subclasses: + * + * * {@link AbstractPerProfileDatabaseProvider} provides a simple abstraction for + * querying databases that are stored in the user's profile directory. + * * {@link PerProfileDatabaseProvider} is a simple version that only allows a + * single ContentProvider to access each per-profile database. + * * {@link SharedBrowserDatabaseProvider} is an example of a per-profile provider + * that allows for multiple providers to safely work with the same databases. */ -public abstract class TransactionalProvider extends ContentProvider { +@SuppressWarnings("javadoc") +public abstract class AbstractTransactionalProvider extends ContentProvider { private static final String LOGTAG = "GeckoTransProvider"; - protected Context mContext; - protected PerProfileDatabases mDatabases; - /* - * Returns the name of the database file. Used to get a path - * to the DB file. - * - * @return name of the database file - */ - abstract protected String getDatabaseName(); + private static boolean logDebug = Log.isLoggable(LOGTAG, Log.DEBUG); + private static boolean logVerbose = Log.isLoggable(LOGTAG, Log.VERBOSE); - /* - * Creates and returns an instance of a DB helper. Given a - * context and a path to the DB file - * - * @param context to use to create the database helper - * @param databasePath path to the DB file - * @return instance of the database helper - */ - abstract protected T createDatabaseHelper(Context context, String databasePath); + protected abstract SQLiteDatabase getReadableDatabase(Uri uri); + protected abstract SQLiteDatabase getWritableDatabase(Uri uri); - /* - * Inserts an item into the database within a DB transaction. - * - * @param uri query URI - * @param values column values to be inserted - * @return a URI for the newly inserted item - */ - abstract protected Uri insertInTransaction(Uri uri, ContentValues values); + public abstract SQLiteDatabase getWritableDatabaseForTesting(Uri uri); - /* - * Deletes items from the database within a DB transaction. - * - * @param uri Query URI. - * @param selection An optional filter to match rows to delete. - * @param selectionArgs An array of arguments to substitute into the selection. - * - * @return number of rows impacted by the deletion. - */ - abstract protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs); - - /* - * Updates the database within a DB transaction. - * - * @param uri Query URI. - * @param values A set of column_name/value pairs to add to the database. - * @param selection An optional filter to match rows to update. - * @param selectionArgs An array of arguments to substitute into the selection. - * - * @return number of rows impacted by the update. - */ - abstract protected int updateInTransaction(Uri uri, ContentValues values, String selection, String[] selectionArgs); - - /* - * Fetches a readable database based on the profile indicated in the - * passed URI. If the URI does not contain a profile param, the default profile - * is used. - * - * @param uri content URI optionally indicating the profile of the user - * @return instance of a readable SQLiteDatabase - */ - protected SQLiteDatabase getReadableDatabase(Uri uri) { - String profile = null; - if (uri != null) { - profile = uri.getQueryParameter(BrowserContract.PARAM_PROFILE); - } - - return mDatabases.getDatabaseHelperForProfile(profile, isTest(uri)).getReadableDatabase(); - } - - /* - * Fetches a writeable database based on the profile indicated in the - * passed URI. If the URI does not contain a profile param, the default profile - * is used - * - * @param uri content URI optionally indicating the profile of the user - * @return instance of a writeable SQLiteDatabase - */ - protected SQLiteDatabase getWritableDatabase(Uri uri) { - String profile = null; - if (uri != null) { - profile = uri.getQueryParameter(BrowserContract.PARAM_PROFILE); - } - - return mDatabases.getDatabaseHelperForProfile(profile, isTest(uri)).getWritableDatabase(); - } - - /** - * Public version of {@link #getWritableDatabase(Uri) getWritableDatabase}. - * This method should ONLY be used for testing purposes. - * - * @param uri content URI optionally indicating the profile of the user - * @return instance of a writeable SQLiteDatabase - */ - @RobocopTarget - public SQLiteDatabase getWritableDatabaseForTesting(Uri uri) { - return getWritableDatabase(uri); - } - - /** - * Return true of the query is from Firefox Sync. - * @param uri query URI - */ - public static boolean isCallerSync(Uri uri) { - String isSync = uri.getQueryParameter(BrowserContract.PARAM_IS_SYNC); - return !TextUtils.isEmpty(isSync); - } - - /** - * Indicates whether a query should include deleted fields - * based on the URI. - * @param uri query URI - */ - public static boolean shouldShowDeleted(Uri uri) { - String showDeleted = uri.getQueryParameter(BrowserContract.PARAM_SHOW_DELETED); - return !TextUtils.isEmpty(showDeleted); - } - - /** - * Indicates whether an insertion should be made if a record doesn't - * exist, based on the URI. - * @param uri query URI - */ - public static boolean shouldUpdateOrInsert(Uri uri) { - String insertIfNeeded = uri.getQueryParameter(BrowserContract.PARAM_INSERT_IF_NEEDED); - return Boolean.parseBoolean(insertIfNeeded); - } - - /** - * Indicates whether query is a test based on the URI. - * @param uri query URI - */ - public static boolean isTest(Uri uri) { - String isTest = uri.getQueryParameter(BrowserContract.PARAM_IS_TEST); - return !TextUtils.isEmpty(isTest); - } - - protected SQLiteDatabase getWritableDatabaseForProfile(String profile, boolean isTest) { - return mDatabases.getDatabaseHelperForProfile(profile, isTest).getWritableDatabase(); - } - - @Override - public boolean onCreate() { - synchronized (this) { - mContext = getContext(); - mDatabases = new PerProfileDatabases( - getContext(), getDatabaseName(), new DatabaseHelperFactory() { - @Override - public T makeDatabaseHelper(Context context, String databasePath) { - return createDatabaseHelper(context, databasePath); - } - }); - } - - return true; - } - - /** - * Return true if OS version and database parallelism support indicates - * that this provider should bundle writes into transactions. - */ - @SuppressWarnings("static-method") - protected boolean shouldUseTransactions() { - return Build.VERSION.SDK_INT >= 11; - } + protected abstract Uri insertInTransaction(Uri uri, ContentValues values); + protected abstract int deleteInTransaction(Uri uri, String selection, String[] selectionArgs); + protected abstract int updateInTransaction(Uri uri, ContentValues values, String selection, String[] selectionArgs); /** * Track whether we're in a batch operation. @@ -222,6 +89,29 @@ public abstract class TransactionalProvider extends */ final ThreadLocal isInBatchOperation = new ThreadLocal(); + /** + * Return true if OS version and database parallelism support indicates + * that this provider should bundle writes into transactions. + */ + @SuppressWarnings("static-method") + protected boolean shouldUseTransactions() { + return Build.VERSION.SDK_INT >= 11; + } + + protected static String computeSQLInClause(int items, String field) { + final StringBuilder builder = new StringBuilder(field); + builder.append(" IN ("); + int i = 0; + for (; i < items - 1; ++i) { + builder.append("?, "); + } + if (i < items) { + builder.append("?"); + } + builder.append(")"); + return builder.toString(); + } + private boolean isInBatch() { final Boolean isInBatch = isInBatchOperation.get(); if (isInBatch == null) { @@ -265,7 +155,7 @@ public abstract class TransactionalProvider extends * If we're not in a batch, but we are in a write transaction, * end it. * - * @see TransactionalProvider#markWriteSuccessful(SQLiteDatabase) + * @see PerProfileDatabaseProvider#markWriteSuccessful(SQLiteDatabase) */ protected void endWrite(final SQLiteDatabase db) { if (isInBatch()) { @@ -301,23 +191,6 @@ public abstract class TransactionalProvider extends isInBatchOperation.set(Boolean.FALSE); } - /* - * This utility is replicated from RepoUtils, which is managed by android-sync. - */ - protected static String computeSQLInClause(int items, String field) { - final StringBuilder builder = new StringBuilder(field); - builder.append(" IN ("); - int i = 0; - for (; i < items - 1; ++i) { - builder.append("?, "); - } - if (i < items) { - builder.append("?"); - } - builder.append(")"); - return builder.toString(); - } - /** * Turn a single-column cursor of longs into a single SQL "IN" clause. * We can do this without using selection arguments because Long isn't @@ -385,10 +258,8 @@ public abstract class TransactionalProvider extends return result; } - @Override - public int update(Uri uri, ContentValues values, String selection, - String[] selectionArgs) { + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { trace("Calling update on URI: " + uri + ", " + selection + ", " + selectionArgs); final SQLiteDatabase db = getWritableDatabase(uri); @@ -438,71 +309,53 @@ public abstract class TransactionalProvider extends if (successes > 0) { final boolean shouldSyncToNetwork = !isCallerSync(uri); - mContext.getContentResolver().notifyChange(uri, null, shouldSyncToNetwork); + getContext().getContentResolver().notifyChange(uri, null, shouldSyncToNetwork); } return successes; } /** - * Clean up some deleted records from the specified table. - * - * If called in an existing transaction, it is the caller's responsibility - * to ensure that the transaction is already upgraded to a writer, because - * this method issues a read followed by a write, and thus is potentially - * vulnerable to an unhandled SQLITE_BUSY failure during the upgrade. - * - * If not called in an existing transaction, no new explicit transaction - * will be begun. + * Indicates whether a query should include deleted fields + * based on the URI. + * @param uri query URI */ - protected void cleanupSomeDeletedRecords(Uri fromUri, Uri targetUri, String tableName) { - Log.d(LOGTAG, "Cleaning up deleted records from " + tableName); - - // We clean up records marked as deleted that are older than a - // predefined max age. It's important not be too greedy here and - // remove only a few old deleted records at a time. - - // we cleanup records marked as deleted that are older than a - // predefined max age. It's important not be too greedy here and - // remove only a few old deleted records at a time. - - // Maximum age of deleted records to be cleaned up (20 days in ms) - final long MAX_AGE_OF_DELETED_RECORDS = 86400000 * 20; - - // Number of records marked as deleted to be removed - final long DELETED_RECORDS_PURGE_LIMIT = 5; - - // Android SQLite doesn't have LIMIT on DELETE. Instead, query for the - // IDs of matching rows, then delete them in one go. - final long now = System.currentTimeMillis(); - final String selection = SyncColumns.IS_DELETED + " = 1 AND " + - SyncColumns.DATE_MODIFIED + " <= " + - (now - MAX_AGE_OF_DELETED_RECORDS); - - final String profile = fromUri.getQueryParameter(BrowserContract.PARAM_PROFILE); - final SQLiteDatabase db = getWritableDatabaseForProfile(profile, isTest(fromUri)); - final String[] ids; - final String limit = Long.toString(DELETED_RECORDS_PURGE_LIMIT, 10); - final Cursor cursor = db.query(tableName, new String[] { CommonColumns._ID }, selection, null, null, null, null, limit); - try { - ids = new String[cursor.getCount()]; - int i = 0; - while (cursor.moveToNext()) { - ids[i++] = Long.toString(cursor.getLong(0), 10); - } - } finally { - cursor.close(); - } - - final String inClause = computeSQLInClause(ids.length, - CommonColumns._ID); - db.delete(tableName, inClause, ids); + protected static boolean shouldShowDeleted(Uri uri) { + String showDeleted = uri.getQueryParameter(BrowserContract.PARAM_SHOW_DELETED); + return !TextUtils.isEmpty(showDeleted); + } + + /** + * Indicates whether an insertion should be made if a record doesn't + * exist, based on the URI. + * @param uri query URI + */ + protected static boolean shouldUpdateOrInsert(Uri uri) { + String insertIfNeeded = uri.getQueryParameter(BrowserContract.PARAM_INSERT_IF_NEEDED); + return Boolean.parseBoolean(insertIfNeeded); + } + + /** + * Indicates whether query is a test based on the URI. + * @param uri query URI + */ + protected static boolean isTest(Uri uri) { + if (uri == null) { + return false; + } + String isTest = uri.getQueryParameter(BrowserContract.PARAM_IS_TEST); + return !TextUtils.isEmpty(isTest); + } + + /** + * Return true of the query is from Firefox Sync. + * @param uri query URI + */ + protected static boolean isCallerSync(Uri uri) { + String isSync = uri.getQueryParameter(BrowserContract.PARAM_IS_SYNC); + return !TextUtils.isEmpty(isSync); } - // Calculate these once, at initialization. isLoggable is too expensive to - // have in-line in each log call. - private static boolean logDebug = Log.isLoggable(LOGTAG, Log.DEBUG); - private static boolean logVerbose = Log.isLoggable(LOGTAG, Log.VERBOSE); protected static void trace(String message) { if (logVerbose) { Log.v(LOGTAG, message); @@ -514,4 +367,4 @@ public abstract class TransactionalProvider extends Log.d(LOGTAG, message); } } -} +} \ No newline at end of file diff --git a/mobile/android/base/db/BrowserProvider.java b/mobile/android/base/db/BrowserProvider.java index fcf9eb3e5be..542c2238ac1 100644 --- a/mobile/android/base/db/BrowserProvider.java +++ b/mobile/android/base/db/BrowserProvider.java @@ -19,7 +19,6 @@ import org.mozilla.gecko.db.BrowserContract.History; import org.mozilla.gecko.db.BrowserContract.Schema; import org.mozilla.gecko.db.BrowserContract.SyncColumns; import org.mozilla.gecko.db.BrowserContract.Thumbnails; -import org.mozilla.gecko.db.BrowserContract.URLColumns; import org.mozilla.gecko.sync.Utils; import android.app.SearchManager; @@ -27,7 +26,6 @@ import android.content.ContentProviderOperation; import android.content.ContentProviderResult; import android.content.ContentUris; import android.content.ContentValues; -import android.content.Context; import android.content.OperationApplicationException; import android.content.UriMatcher; import android.database.Cursor; @@ -40,7 +38,7 @@ import android.net.Uri; import android.text.TextUtils; import android.util.Log; -public class BrowserProvider extends TransactionalProvider { +public class BrowserProvider extends SharedBrowserDatabaseProvider { private static final String LOGTAG = "GeckoBrowserProvider"; // How many records to reposition in a single query. @@ -815,21 +813,6 @@ public class BrowserProvider extends TransactionalProvider extends AbstractPerProfileDatabaseProvider { + private PerProfileDatabases databases; + + @Override + protected PerProfileDatabases getDatabases() { + return databases; + } + + protected abstract String getDatabaseName(); + + /** + * Creates and returns an instance of the appropriate DB helper. + * + * @param context to use to create the database helper + * @param databasePath path to the DB file + * @return instance of the database helper + */ + protected abstract T createDatabaseHelper(Context context, String databasePath); + + @Override + public boolean onCreate() { + synchronized (this) { + databases = new PerProfileDatabases( + getContext(), getDatabaseName(), new DatabaseHelperFactory() { + @Override + public T makeDatabaseHelper(Context context, String databasePath) { + return createDatabaseHelper(context, databasePath); + } + }); + } + + return true; + } +} diff --git a/mobile/android/base/db/ReadingListProvider.java b/mobile/android/base/db/ReadingListProvider.java index b2864923686..f17e75ddce6 100644 --- a/mobile/android/base/db/ReadingListProvider.java +++ b/mobile/android/base/db/ReadingListProvider.java @@ -9,7 +9,6 @@ import org.mozilla.gecko.sync.Utils; import android.content.ContentUris; import android.content.ContentValues; -import android.content.Context; import android.content.UriMatcher; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; @@ -17,9 +16,7 @@ import android.database.sqlite.SQLiteQueryBuilder; import android.net.Uri; import android.text.TextUtils; -public class ReadingListProvider extends TransactionalProvider { - private static final String LOGTAG = "GeckoReadingListProv"; - +public class ReadingListProvider extends SharedBrowserDatabaseProvider { static final String TABLE_READING_LIST = ReadingListItems.TABLE_NAME; static final int ITEMS = 101; @@ -103,7 +100,7 @@ public class ReadingListProvider extends TransactionalProvider databases; + + @Override + protected PerProfileDatabases getDatabases() { + return databases; + } + + @Override + public boolean onCreate() { + // If necessary, do the shared DB work. + synchronized (SharedBrowserDatabaseProvider.class) { + if (databases != null) { + return true; + } + + final DatabaseHelperFactory helperFactory = new DatabaseHelperFactory() { + @Override + public BrowserDatabaseHelper makeDatabaseHelper(Context context, String databasePath) { + return new BrowserDatabaseHelper(context, databasePath); + } + }; + + databases = new PerProfileDatabases(getContext(), BrowserDatabaseHelper.DATABASE_NAME, helperFactory); + } + + return true; + } + + /** + * Clean up some deleted records from the specified table. + * + * If called in an existing transaction, it is the caller's responsibility + * to ensure that the transaction is already upgraded to a writer, because + * this method issues a read followed by a write, and thus is potentially + * vulnerable to an unhandled SQLITE_BUSY failure during the upgrade. + * + * If not called in an existing transaction, no new explicit transaction + * will be begun. + */ + protected void cleanUpSomeDeletedRecords(Uri fromUri, String tableName) { + Log.d(LOGTAG, "Cleaning up deleted records from " + tableName); + + // We clean up records marked as deleted that are older than a + // predefined max age. It's important not be too greedy here and + // remove only a few old deleted records at a time. + + // we cleanup records marked as deleted that are older than a + // predefined max age. It's important not be too greedy here and + // remove only a few old deleted records at a time. + + // Maximum age of deleted records to be cleaned up (20 days in ms) + final long MAX_AGE_OF_DELETED_RECORDS = 86400000 * 20; + + // Number of records marked as deleted to be removed + final long DELETED_RECORDS_PURGE_LIMIT = 5; + + // Android SQLite doesn't have LIMIT on DELETE. Instead, query for the + // IDs of matching rows, then delete them in one go. + final long now = System.currentTimeMillis(); + final String selection = SyncColumns.IS_DELETED + " = 1 AND " + + SyncColumns.DATE_MODIFIED + " <= " + + (now - MAX_AGE_OF_DELETED_RECORDS); + + final String profile = fromUri.getQueryParameter(BrowserContract.PARAM_PROFILE); + final SQLiteDatabase db = getWritableDatabaseForProfile(profile, isTest(fromUri)); + final String[] ids; + final String limit = Long.toString(DELETED_RECORDS_PURGE_LIMIT, 10); + final Cursor cursor = db.query(tableName, new String[] { CommonColumns._ID }, selection, null, null, null, null, limit); + try { + ids = new String[cursor.getCount()]; + int i = 0; + while (cursor.moveToNext()) { + ids[i++] = Long.toString(cursor.getLong(0), 10); + } + } finally { + cursor.close(); + } + + final String inClause = computeSQLInClause(ids.length, + CommonColumns._ID); + db.delete(tableName, inClause, ids); + } +} diff --git a/mobile/android/base/db/TabsProvider.java b/mobile/android/base/db/TabsProvider.java index 34df1cbfd91..9b1a05fbb2f 100644 --- a/mobile/android/base/db/TabsProvider.java +++ b/mobile/android/base/db/TabsProvider.java @@ -4,37 +4,25 @@ package org.mozilla.gecko.db; -import java.io.File; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import org.mozilla.gecko.GeckoProfile; import org.mozilla.gecko.db.BrowserContract.Clients; import org.mozilla.gecko.db.BrowserContract.Tabs; -import org.mozilla.gecko.db.PerProfileDatabases.DatabaseHelperFactory; -import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.UriMatcher; import android.database.Cursor; -import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteQueryBuilder; import android.net.Uri; -import android.os.Build; import android.text.TextUtils; -import android.util.Log; - -public class TabsProvider extends ContentProvider { - private static final String LOGTAG = "GeckoTabsProvider"; - private Context mContext; - - private PerProfileDatabases mDatabases; +public class TabsProvider extends PerProfileDatabaseProvider { static final String DATABASE_NAME = "tabs.db"; static final int DATABASE_VERSION = 2; @@ -87,35 +75,10 @@ public class TabsProvider extends ContentProvider { CLIENTS_PROJECTION_MAP = Collections.unmodifiableMap(map); } - static final String selectColumn(String table, String column) { + private static final String selectColumn(String table, String column) { return table + "." + column + " = ?"; } - // Calculate these once, at initialization. isLoggable is too expensive to - // have in-line in each log call. - private static boolean logDebug = Log.isLoggable(LOGTAG, Log.DEBUG); - private static boolean logVerbose = Log.isLoggable(LOGTAG, Log.VERBOSE); - protected static void trace(String message) { - if (logVerbose) { - Log.v(LOGTAG, message); - } - } - - protected static void debug(String message) { - if (logDebug) { - Log.d(LOGTAG, message); - } - } - - /** - * Return true of the query is from Firefox Sync. - * @param uri query URI - */ - public static boolean isCallerSync(Uri uri) { - String isSync = uri.getQueryParameter(BrowserContract.PARAM_IS_SYNC); - return !TextUtils.isEmpty(isSync); - } - final class TabsDatabaseHelper extends SQLiteOpenHelper { public TabsDatabaseHelper(Context context, String databasePath) { super(context, databasePath, null, DATABASE_VERSION); @@ -128,35 +91,34 @@ public class TabsProvider extends ContentProvider { // Table for each tab on any client. db.execSQL("CREATE TABLE " + TABLE_TABS + "(" + - Tabs._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + - Tabs.CLIENT_GUID + " TEXT," + - Tabs.TITLE + " TEXT," + - Tabs.URL + " TEXT," + - Tabs.HISTORY + " TEXT," + - Tabs.FAVICON + " TEXT," + - Tabs.LAST_USED + " INTEGER," + - Tabs.POSITION + " INTEGER" + - ");"); + Tabs._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + + Tabs.CLIENT_GUID + " TEXT," + + Tabs.TITLE + " TEXT," + + Tabs.URL + " TEXT," + + Tabs.HISTORY + " TEXT," + + Tabs.FAVICON + " TEXT," + + Tabs.LAST_USED + " INTEGER," + + Tabs.POSITION + " INTEGER" + + ");"); // Indices on CLIENT_GUID and POSITION. - db.execSQL("CREATE INDEX " + INDEX_TABS_GUID + " ON " + TABLE_TABS + "(" - + Tabs.CLIENT_GUID + ")"); - - db.execSQL("CREATE INDEX " + INDEX_TABS_POSITION + " ON " + TABLE_TABS + "(" - + Tabs.POSITION + ")"); + db.execSQL("CREATE INDEX " + INDEX_TABS_GUID + + " ON " + TABLE_TABS + "(" + Tabs.CLIENT_GUID + ")"); + db.execSQL("CREATE INDEX " + INDEX_TABS_POSITION + + " ON " + TABLE_TABS + "(" + Tabs.POSITION + ")"); debug("Creating " + TABLE_CLIENTS + " table"); // Table for client's name-guid mapping. db.execSQL("CREATE TABLE " + TABLE_CLIENTS + "(" + - Clients.GUID + " TEXT PRIMARY KEY," + - Clients.NAME + " TEXT," + - Clients.LAST_MODIFIED + " INTEGER" + - ");"); + Clients.GUID + " TEXT PRIMARY KEY," + + Clients.NAME + " TEXT," + + Clients.LAST_MODIFIED + " INTEGER" + + ");"); // Index on GUID. - db.execSQL("CREATE INDEX " + INDEX_CLIENTS_GUID + " ON " + TABLE_CLIENTS + "(" - + Clients.GUID + ")"); + db.execSQL("CREATE INDEX " + INDEX_CLIENTS_GUID + + " ON " + TABLE_CLIENTS + "(" + Clients.GUID + ")"); createLocalClient(db); } @@ -173,7 +135,7 @@ public class TabsProvider extends ContentProvider { @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { debug("Upgrading tabs.db: " + db.getPath() + " from " + - oldVersion + " to " + newVersion); + oldVersion + " to " + newVersion); // We have to do incremental upgrades until we reach the current // database schema version. @@ -189,73 +151,20 @@ public class TabsProvider extends ContentProvider { @Override public void onOpen(SQLiteDatabase db) { debug("Opening tabs.db: " + db.getPath()); + db.rawQuery("PRAGMA synchronous=OFF", null).close(); - Cursor cursor = null; - try { - cursor = db.rawQuery("PRAGMA synchronous=OFF", null); - } finally { - if (cursor != null) - cursor.close(); - } - - // From Honeycomb on, it's possible to run several db - // commands in parallel using multiple connections. - if (Build.VERSION.SDK_INT >= 11) { + if (shouldUseTransactions()) { db.enableWriteAheadLogging(); db.setLockingEnabled(false); - } else { - // Pre-Honeycomb, we can do some lesser optimizations. - cursor = null; - try { - cursor = db.rawQuery("PRAGMA journal_mode=PERSIST", null); - } finally { - if (cursor != null) - cursor.close(); - } + return; } + + // If we're not using transactions (in particular, prior to + // Honeycomb), then we can do some lesser optimizations. + db.rawQuery("PRAGMA journal_mode=PERSIST", null).close(); } } - private SQLiteDatabase getReadableDatabase(Uri uri) { - trace("Getting readable database for URI: " + uri); - - String profile = null; - - if (uri != null) - profile = uri.getQueryParameter(BrowserContract.PARAM_PROFILE); - - return mDatabases.getDatabaseHelperForProfile(profile).getReadableDatabase(); - } - - private SQLiteDatabase getWritableDatabase(Uri uri) { - trace("Getting writable database for URI: " + uri); - - String profile = null; - - if (uri != null) - profile = uri.getQueryParameter(BrowserContract.PARAM_PROFILE); - - return mDatabases.getDatabaseHelperForProfile(profile).getWritableDatabase(); - } - - @Override - public boolean onCreate() { - debug("Creating TabsProvider"); - - synchronized (this) { - mContext = getContext(); - mDatabases = new PerProfileDatabases( - getContext(), DATABASE_NAME, new DatabaseHelperFactory() { - @Override - public TabsDatabaseHelper makeDatabaseHelper(Context context, String databasePath) { - return new TabsDatabaseHelper(context, databasePath); - } - }); - } - - return true; - } - @Override public String getType(Uri uri) { final int match = URI_MATCHER.match(uri); @@ -285,35 +194,6 @@ public class TabsProvider extends ContentProvider { return null; } - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - trace("Calling delete on URI: " + uri); - - final SQLiteDatabase db = getWritableDatabase(uri); - int deleted = 0; - - if (Build.VERSION.SDK_INT >= 11) { - trace("Beginning delete transaction: " + uri); - db.beginTransaction(); - try { - deleted = deleteInTransaction(uri, selection, selectionArgs); - db.setTransactionSuccessful(); - trace("Successful delete transaction: " + uri); - } finally { - db.endTransaction(); - } - } else { - deleted = deleteInTransaction(uri, selection, selectionArgs); - } - - if (deleted > 0) { - final boolean shouldSyncToNetwork = !isCallerSync(uri); - getContext().getContentResolver().notifyChange(uri, null, shouldSyncToNetwork); - } - - return deleted; - } - @SuppressWarnings("fallthrough") public int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) { trace("Calling delete in transaction on URI: " + uri); @@ -355,35 +235,6 @@ public class TabsProvider extends ContentProvider { return deleted; } - @Override - public Uri insert(Uri uri, ContentValues values) { - trace("Calling insert on URI: " + uri); - - final SQLiteDatabase db = getWritableDatabase(uri); - Uri result = null; - - if (Build.VERSION.SDK_INT >= 11) { - trace("Beginning insert transaction: " + uri); - db.beginTransaction(); - try { - result = insertInTransaction(uri, values); - db.setTransactionSuccessful(); - trace("Successful insert transaction: " + uri); - } finally { - db.endTransaction(); - } - } else { - result = insertInTransaction(uri, values); - } - - if (result != null) { - final boolean shouldSyncToNetwork = !isCallerSync(uri); - getContext().getContentResolver().notifyChange(uri, null, shouldSyncToNetwork); - } - - return result; - } - public Uri insertInTransaction(Uri uri, ContentValues values) { trace("Calling insert in transaction on URI: " + uri); @@ -416,38 +267,7 @@ public class TabsProvider extends ContentProvider { return null; } - @Override - public int update(Uri uri, ContentValues values, String selection, - String[] selectionArgs) { - trace("Calling update on URI: " + uri); - - final SQLiteDatabase db = getWritableDatabase(uri); - int updated = 0; - - if (Build.VERSION.SDK_INT >= 11) { - trace("Beginning update transaction: " + uri); - db.beginTransaction(); - try { - updated = updateInTransaction(uri, values, selection, selectionArgs); - db.setTransactionSuccessful(); - trace("Successful update transaction: " + uri); - } finally { - db.endTransaction(); - } - } else { - updated = updateInTransaction(uri, values, selection, selectionArgs); - } - - if (updated > 0) { - final boolean shouldSyncToNetwork = !isCallerSync(uri); - getContext().getContentResolver().notifyChange(uri, null, shouldSyncToNetwork); - } - - return updated; - } - - public int updateInTransaction(Uri uri, ContentValues values, String selection, - String[] selectionArgs) { + public int updateInTransaction(Uri uri, ContentValues values, String selection, String[] selectionArgs) { trace("Calling update in transaction on URI: " + uri); int match = URI_MATCHER.match(uri); @@ -537,10 +357,8 @@ public class TabsProvider extends ContentProvider { } trace("Running built query."); - Cursor cursor = qb.query(db, projection, selection, selectionArgs, null, - null, sortOrder, limit); - cursor.setNotificationUri(getContext().getContentResolver(), - BrowserContract.TABS_AUTHORITY_URI); + final Cursor cursor = qb.query(db, projection, selection, selectionArgs, null, null, sortOrder, limit); + cursor.setNotificationUri(getContext().getContentResolver(), BrowserContract.TABS_AUTHORITY_URI); return cursor; } @@ -549,7 +367,7 @@ public class TabsProvider extends ContentProvider { trace("Updating tabs on URI: " + uri); final SQLiteDatabase db = getWritableDatabase(uri); - + beginWrite(db); return db.update(table, values, selection, selectionArgs); } @@ -557,46 +375,17 @@ public class TabsProvider extends ContentProvider { debug("Deleting tabs for URI: " + uri); final SQLiteDatabase db = getWritableDatabase(uri); - + beginWrite(db); return db.delete(table, selection, selectionArgs); } @Override - public int bulkInsert(Uri uri, ContentValues[] values) { - if (values == null) - return 0; + protected TabsDatabaseHelper createDatabaseHelper(Context context, String databasePath) { + return new TabsDatabaseHelper(context, databasePath); + } - int numValues = values.length; - int successes = 0; - - final SQLiteDatabase db = getWritableDatabase(uri); - - db.beginTransaction(); - try { - for (int i = 0; i < numValues; i++) { - try { - insertInTransaction(uri, values[i]); - successes++; - } catch (SQLException e) { - Log.e(LOGTAG, "SQLException in bulkInsert", e); - - // Restart the transaction to continue insertions. - db.setTransactionSuccessful(); - db.endTransaction(); - db.beginTransaction(); - } - } - trace("Flushing DB bulkinsert..."); - db.setTransactionSuccessful(); - } finally { - db.endTransaction(); - } - - if (successes > 0) { - final boolean shouldSyncToNetwork = !isCallerSync(uri); - mContext.getContentResolver().notifyChange(uri, null, shouldSyncToNetwork); - } - - return successes; + @Override + protected String getDatabaseName() { + return DATABASE_NAME; } } diff --git a/mobile/android/base/fxa/activities/FxAccountUpdateCredentialsActivity.java b/mobile/android/base/fxa/activities/FxAccountUpdateCredentialsActivity.java index 4fef6ae5c49..dee943f59dc 100644 --- a/mobile/android/base/fxa/activities/FxAccountUpdateCredentialsActivity.java +++ b/mobile/android/base/fxa/activities/FxAccountUpdateCredentialsActivity.java @@ -115,7 +115,14 @@ public class FxAccountUpdateCredentialsActivity extends FxAccountAbstractSetupAc @Override public void handleFailure(FxAccountClientRemoteException e) { - // TODO On isUpgradeRequired, transition to Doghouse state. + if (e.isUpgradeRequired()) { + Logger.error(LOG_TAG, "Got upgrade required from remote server; transitioning Firefox Account to Doghouse state."); + final State state = fxAccount.getState(); + fxAccount.setState(state.makeDoghouseState()); + // The status activity will say that the user needs to upgrade. + redirectToActivity(FxAccountStatusActivity.class); + return; + } showRemoteError(e, R.string.fxaccount_update_credentials_unknown_error); } diff --git a/mobile/android/base/fxa/authenticator/AndroidFxAccount.java b/mobile/android/base/fxa/authenticator/AndroidFxAccount.java index 8292e02fdfa..834a51767b5 100644 --- a/mobile/android/base/fxa/authenticator/AndroidFxAccount.java +++ b/mobile/android/base/fxa/authenticator/AndroidFxAccount.java @@ -398,7 +398,7 @@ public class AndroidFxAccount { } public void enableSyncing() { - Logger.info(LOG_TAG, "Enabling sync for account named like " + Utils.obfuscateEmail(getEmail())); + Logger.info(LOG_TAG, "Enabling sync for account named like " + getObfuscatedEmail()); for (String authority : new String[] { BrowserContract.AUTHORITY }) { ContentResolver.setSyncAutomatically(account, authority, true); ContentResolver.setIsSyncable(account, authority, 1); @@ -406,14 +406,14 @@ public class AndroidFxAccount { } public void disableSyncing() { - Logger.info(LOG_TAG, "Disabling sync for account named like " + Utils.obfuscateEmail(getEmail())); + Logger.info(LOG_TAG, "Disabling sync for account named like " + getObfuscatedEmail()); for (String authority : new String[] { BrowserContract.AUTHORITY }) { ContentResolver.setSyncAutomatically(account, authority, false); } } public void requestSync(Bundle extras) { - Logger.info(LOG_TAG, "Requesting sync for account named like " + Utils.obfuscateEmail(getEmail()) + + Logger.info(LOG_TAG, "Requesting sync for account named like " + getObfuscatedEmail() + (extras.isEmpty() ? "." : "; has extras.")); for (String authority : new String[] { BrowserContract.AUTHORITY }) { ContentResolver.requestSync(account, authority, extras); @@ -424,7 +424,7 @@ public class AndroidFxAccount { if (state == null) { throw new IllegalArgumentException("state must not be null"); } - Logger.info(LOG_TAG, "Moving account named like " + Utils.obfuscateEmail(getEmail()) + + Logger.info(LOG_TAG, "Moving account named like " + getObfuscatedEmail() + " to state " + state.getStateLabel().toString()); updateBundleValue(BUNDLE_KEY_STATE_LABEL, state.getStateLabel().name()); updateBundleValue(BUNDLE_KEY_STATE, state.toJSONObject().toJSONString()); @@ -475,6 +475,17 @@ public class AndroidFxAccount { return account.name; } + /** + * Return the Firefox Account's local email address, obfuscated. + *

+ * Use this when logging. + * + * @return local email address, obfuscated. + */ + public String getObfuscatedEmail() { + return Utils.obfuscateEmail(account.name); + } + /** * Create an intent announcing that a Firefox account will be deleted. * diff --git a/mobile/android/base/fxa/receivers/FxAccountUpgradeReceiver.java b/mobile/android/base/fxa/receivers/FxAccountUpgradeReceiver.java new file mode 100644 index 00000000000..41f6977ce17 --- /dev/null +++ b/mobile/android/base/fxa/receivers/FxAccountUpgradeReceiver.java @@ -0,0 +1,132 @@ +/* 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/. */ + +package org.mozilla.gecko.fxa.receivers; + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +import org.mozilla.gecko.background.common.log.Logger; +import org.mozilla.gecko.fxa.FirefoxAccounts; +import org.mozilla.gecko.fxa.FxAccountConstants; +import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount; +import org.mozilla.gecko.fxa.login.State; +import org.mozilla.gecko.fxa.login.State.StateLabel; +import org.mozilla.gecko.sync.Utils; + +import android.accounts.Account; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +/** + * A receiver that takes action when our Android package is upgraded (replaced). + */ +public class FxAccountUpgradeReceiver extends BroadcastReceiver { + private static final String LOG_TAG = FxAccountUpgradeReceiver.class.getSimpleName(); + + /** + * Produce a list of Runnable instances to be executed sequentially on + * upgrade. + *

+ * Each Runnable will be executed sequentially on a background thread. Any + * unchecked Exception thrown will be caught and ignored. + * + * @param context Android context. + * @return list of Runnable instances. + */ + protected List onUpgradeRunnables(Context context) { + List runnables = new LinkedList(); + runnables.add(new MaybeUnpickleRunnable(context)); + // Recovering accounts that are in the Doghouse should happen *after* we + // unpickle any accounts saved to disk. + runnables.add(new AdvanceFromDoghouseRunnable(context)); + return runnables; + } + + @Override + public void onReceive(final Context context, Intent intent) { + Logger.setThreadLogTag(FxAccountConstants.GLOBAL_LOG_TAG); + Logger.info(LOG_TAG, "Upgrade broadcast received."); + + // Iterate Runnable instances one at a time. + final Executor executor = Executors.newSingleThreadExecutor(); + for (final Runnable runnable : onUpgradeRunnables(context)) { + executor.execute(new Runnable() { + @Override + public void run() { + try { + runnable.run(); + } catch (Exception e) { + // We really don't want to throw on a background thread, so we + // catch, log, and move on. + Logger.error(LOG_TAG, "Got exception executing background upgrade Runnable; ignoring.", e); + } + } + }); + } + } + + /** + * A Runnable that tries to unpickle any pickled Firefox Accounts. + */ + protected static class MaybeUnpickleRunnable implements Runnable { + protected final Context context; + + public MaybeUnpickleRunnable(Context context) { + this.context = context; + } + + @Override + public void run() { + // Querying the accounts will unpickle any pickled Firefox Account. + Logger.info(LOG_TAG, "Trying to unpickle any pickled Firefox Account."); + FirefoxAccounts.getFirefoxAccounts(context); + } + } + + /** + * A Runnable that tries to advance existing Firefox Accounts that are in the + * Doghouse state to the Separated state. + *

+ * This is our main deprecation-and-upgrade mechanism: in some way, the + * Account gets moved to the Doghouse state. If possible, an upgraded version + * of the package advances to Separated, prompting the user to re-connect the + * Account. + */ + protected static class AdvanceFromDoghouseRunnable implements Runnable { + protected final Context context; + + public AdvanceFromDoghouseRunnable(Context context) { + this.context = context; + } + + @Override + public void run() { + final Account[] accounts = FirefoxAccounts.getFirefoxAccounts(context); + Logger.info(LOG_TAG, "Trying to advance " + accounts.length + " existing Firefox Accounts from the Doghouse to Separated (if necessary)."); + for (Account account : accounts) { + try { + final AndroidFxAccount fxAccount = new AndroidFxAccount(context, account); + // For great debugging. + if (FxAccountConstants.LOG_PERSONAL_INFORMATION) { + fxAccount.dump(); + } + State state = fxAccount.getState(); + if (state == null || state.getStateLabel() != StateLabel.Doghouse) { + Logger.debug(LOG_TAG, "Account named like " + Utils.obfuscateEmail(account.name) + " is not in the Doghouse; skipping."); + continue; + } + Logger.debug(LOG_TAG, "Account named like " + Utils.obfuscateEmail(account.name) + " is in the Doghouse; advancing to Separated."); + fxAccount.setState(state.makeSeparatedState()); + } catch (Exception e) { + Logger.warn(LOG_TAG, "Got exception trying to advance account named like " + Utils.obfuscateEmail(account.name) + + " from Doghouse to Separated state; ignoring.", e); + } + } + } + } +} diff --git a/mobile/android/base/home/FramePanelLayout.java b/mobile/android/base/home/FramePanelLayout.java index 3b69502f666..f7aed88a567 100644 --- a/mobile/android/base/home/FramePanelLayout.java +++ b/mobile/android/base/home/FramePanelLayout.java @@ -38,8 +38,8 @@ class FramePanelLayout extends PanelLayout { Log.d(LOGTAG, "Loading"); if (mChildView instanceof DatasetBacked) { - // TODO: get filter from ViewEntry - DatasetRequest request = new DatasetRequest(mChildConfig.getDatasetId(), null); + final FilterDetail filter = new FilterDetail(mChildConfig.getFilter(), null); + final DatasetRequest request = new DatasetRequest(mChildConfig.getDatasetId(), filter); Log.d(LOGTAG, "Requesting child request: " + request); requestDataset(request); } diff --git a/mobile/android/base/home/HomeConfig.java b/mobile/android/base/home/HomeConfig.java index a6529907628..7422c24bc24 100644 --- a/mobile/android/base/home/HomeConfig.java +++ b/mobile/android/base/home/HomeConfig.java @@ -608,12 +608,14 @@ public final class HomeConfig { private final ItemType mItemType; private final ItemHandler mItemHandler; private final String mBackImageUrl; + private final String mFilter; private static final String JSON_KEY_TYPE = "type"; private static final String JSON_KEY_DATASET = "dataset"; private static final String JSON_KEY_ITEM_TYPE = "itemType"; private static final String JSON_KEY_ITEM_HANDLER = "itemHandler"; private static final String JSON_KEY_BACK_IMAGE_URL = "backImageUrl"; + private static final String JSON_KEY_FILTER = "filter"; public ViewConfig(JSONObject json) throws JSONException, IllegalArgumentException { mType = ViewType.fromId(json.getString(JSON_KEY_TYPE)); @@ -621,6 +623,7 @@ public final class HomeConfig { mItemType = ItemType.fromId(json.getString(JSON_KEY_ITEM_TYPE)); mItemHandler = ItemHandler.fromId(json.getString(JSON_KEY_ITEM_HANDLER)); mBackImageUrl = json.optString(JSON_KEY_BACK_IMAGE_URL, null); + mFilter = json.optString(JSON_KEY_FILTER, null); validate(); } @@ -632,6 +635,7 @@ public final class HomeConfig { mItemType = (ItemType) in.readParcelable(getClass().getClassLoader()); mItemHandler = (ItemHandler) in.readParcelable(getClass().getClassLoader()); mBackImageUrl = in.readString(); + mFilter = in.readString(); validate(); } @@ -642,17 +646,19 @@ public final class HomeConfig { mItemType = viewConfig.mItemType; mItemHandler = viewConfig.mItemHandler; mBackImageUrl = viewConfig.mBackImageUrl; + mFilter = viewConfig.mFilter; validate(); } public ViewConfig(ViewType type, String datasetId, ItemType itemType, - ItemHandler itemHandler, String backImageUrl) { + ItemHandler itemHandler, String backImageUrl, String filter) { mType = type; mDatasetId = datasetId; mItemType = itemType; mItemHandler = itemHandler; mBackImageUrl = backImageUrl; + mFilter = filter; validate(); } @@ -695,6 +701,10 @@ public final class HomeConfig { return mBackImageUrl; } + public String getFilter() { + return mFilter; + } + public JSONObject toJSON() throws JSONException { final JSONObject json = new JSONObject(); @@ -707,6 +717,10 @@ public final class HomeConfig { json.put(JSON_KEY_BACK_IMAGE_URL, mBackImageUrl); } + if (!TextUtils.isEmpty(mFilter)) { + json.put(JSON_KEY_FILTER, mFilter); + } + return json; } @@ -722,6 +736,7 @@ public final class HomeConfig { dest.writeParcelable(mItemType, 0); dest.writeParcelable(mItemHandler, 0); dest.writeString(mBackImageUrl); + dest.writeString(mFilter); } public static final Creator CREATOR = new Creator() { diff --git a/mobile/android/base/home/PanelLayout.java b/mobile/android/base/home/PanelLayout.java index dd0fceb92cc..ad284d1dfbd 100644 --- a/mobile/android/base/home/PanelLayout.java +++ b/mobile/android/base/home/PanelLayout.java @@ -401,9 +401,9 @@ abstract class PanelLayout extends FrameLayout { if (mFilterStack == null) { mFilterStack = new LinkedList(); - // Initialize with a null filter. - // TODO: use initial filter from ViewConfig - mFilterStack.push(new FilterDetail(null, mPanelConfig.getTitle())); + // Initialize with the initial filter. + mFilterStack.push(new FilterDetail(mViewConfig.getFilter(), + mPanelConfig.getTitle())); } mFilterStack.push(filter); diff --git a/mobile/android/base/moz.build b/mobile/android/base/moz.build index 3bd6f785230..3190848c5b8 100644 --- a/mobile/android/base/moz.build +++ b/mobile/android/base/moz.build @@ -117,6 +117,8 @@ gbjar.sources += [ 'ContextGetter.java', 'CustomEditText.java', 'DataReportingNotification.java', + 'db/AbstractPerProfileDatabaseProvider.java', + 'db/AbstractTransactionalProvider.java', 'db/BrowserContract.java', 'db/BrowserDatabaseHelper.java', 'db/BrowserDB.java', @@ -126,11 +128,12 @@ gbjar.sources += [ 'db/HomeProvider.java', 'db/LocalBrowserDB.java', 'db/PasswordsProvider.java', + 'db/PerProfileDatabaseProvider.java', 'db/PerProfileDatabases.java', 'db/ReadingListProvider.java', + 'db/SharedBrowserDatabaseProvider.java', 'db/SQLiteBridgeContentProvider.java', 'db/TabsProvider.java', - 'db/TransactionalProvider.java', 'Distribution.java', 'DoorHangerPopup.java', 'DynamicToolbar.java', diff --git a/mobile/android/base/resources/drawable-hdpi/progress.9.png b/mobile/android/base/resources/drawable-hdpi/progress.9.png index 42566ff2e33..263b40582d4 100644 Binary files a/mobile/android/base/resources/drawable-hdpi/progress.9.png and b/mobile/android/base/resources/drawable-hdpi/progress.9.png differ diff --git a/mobile/android/base/resources/drawable-mdpi/progress.9.png b/mobile/android/base/resources/drawable-mdpi/progress.9.png index 370898c4a4b..5f877646602 100644 Binary files a/mobile/android/base/resources/drawable-mdpi/progress.9.png and b/mobile/android/base/resources/drawable-mdpi/progress.9.png differ diff --git a/mobile/android/base/resources/drawable-xhdpi/progress.9.png b/mobile/android/base/resources/drawable-xhdpi/progress.9.png index 93546b15fb9..f0e482f092e 100644 Binary files a/mobile/android/base/resources/drawable-xhdpi/progress.9.png and b/mobile/android/base/resources/drawable-xhdpi/progress.9.png differ diff --git a/mobile/android/base/sync/setup/activities/SendTabActivity.java b/mobile/android/base/sync/setup/activities/SendTabActivity.java index 1d6f9c1f434..bd0b36952d7 100644 --- a/mobile/android/base/sync/setup/activities/SendTabActivity.java +++ b/mobile/android/base/sync/setup/activities/SendTabActivity.java @@ -14,7 +14,9 @@ import org.mozilla.gecko.R; import org.mozilla.gecko.background.common.log.Logger; import org.mozilla.gecko.fxa.FxAccountConstants; import org.mozilla.gecko.fxa.activities.FxAccountGetStartedActivity; +import org.mozilla.gecko.fxa.activities.FxAccountStatusActivity; import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount; +import org.mozilla.gecko.fxa.login.State.Action; import org.mozilla.gecko.sync.CommandProcessor; import org.mozilla.gecko.sync.CommandRunner; import org.mozilla.gecko.sync.GlobalSession; @@ -58,17 +60,17 @@ public class SendTabActivity extends Activity { void syncClientsStage(); } - public class FxAccountTabSender implements TabSender { - private final AndroidFxAccount account; + private static class FxAccountTabSender implements TabSender { + private final AndroidFxAccount fxAccount; - public FxAccountTabSender(Context context, Account account) { - this.account = new AndroidFxAccount(context, account); + public FxAccountTabSender(Context context, AndroidFxAccount fxAccount) { + this.fxAccount = fxAccount; } @Override public String getAccountGUID() { try { - final SharedPreferences prefs = this.account.getSyncPrefs(); + final SharedPreferences prefs = this.fxAccount.getSyncPrefs(); return prefs.getString(SyncConfiguration.PREF_ACCOUNT_GUID, null); } catch (Exception e) { Logger.warn(LOG_TAG, "Could not get Firefox Account parameters or preferences; aborting."); @@ -81,7 +83,7 @@ public class SendTabActivity extends Activity { final Bundle extras = new Bundle(); Utils.putStageNamesToSync(extras, CLIENTS_STAGE, null); extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); - this.account.requestSync(extras); + this.fxAccount.requestSync(extras); } } @@ -89,6 +91,7 @@ public class SendTabActivity extends Activity { private final Account account; private final AccountManager accountManager; private final Context context; + private Sync11TabSender(Context context, Account syncAccount, AccountManager accountManager) { this.context = context; this.account = syncAccount; @@ -224,7 +227,17 @@ public class SendTabActivity extends Activity { final Account[] fxAccounts = accountManager.getAccountsByType(FxAccountConstants.ACCOUNT_TYPE); if (fxAccounts.length > 0) { - this.tabSender = new FxAccountTabSender(applicationContext, fxAccounts[0]); + final AndroidFxAccount fxAccount = new AndroidFxAccount(applicationContext, fxAccounts[0]); + if (fxAccount.getState().getNeededAction() != Action.None) { + // We have a Firefox Account, but it's definitely not able to send a tab + // right now. Redirect to the status activity. + Logger.warn(LOG_TAG, "Firefox Account named like " + fxAccount.getObfuscatedEmail() + + " needs action before it can send a tab; redirecting to status activity."); + redirectToNewTask(FxAccountStatusActivity.class, false); + return; + } + + this.tabSender = new FxAccountTabSender(applicationContext, fxAccount); Logger.info(LOG_TAG, "Allowing tab send for Firefox Account."); registerDisplayURICommand(); @@ -241,10 +254,7 @@ public class SendTabActivity extends Activity { } // Offer to set up a Firefox Account, and finish this activity. - final Intent intent = new Intent(applicationContext, FxAccountGetStartedActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(intent); - finish(); + redirectToNewTask(FxAccountGetStartedActivity.class, false); } private static void registerDisplayURICommand() { @@ -379,4 +389,15 @@ public class SendTabActivity extends Activity { } return out; } + + // Adapted from FxAccountAbstractActivity. + protected void redirectToNewTask(Class activityClass, boolean success) { + Intent intent = new Intent(this, activityClass); + // Per http://stackoverflow.com/a/8992365, this triggers a known bug with + // the soft keyboard not being shown for the started activity. Why, Android, why? + intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + notifyAndFinish(success); + } } diff --git a/mobile/android/base/sync/setup/activities/WebViewActivity.java b/mobile/android/base/sync/setup/activities/WebViewActivity.java index f5200bc308c..e1984c1618d 100644 --- a/mobile/android/base/sync/setup/activities/WebViewActivity.java +++ b/mobile/android/base/sync/setup/activities/WebViewActivity.java @@ -33,6 +33,7 @@ public class WebViewActivity extends SyncActivity { if (uri == null) { Logger.debug(LOG_TAG, "No URI passed to display."); finish(); + return; } WebView wv = (WebView) findViewById(R.id.web_engine); diff --git a/mobile/android/base/tests/AboutHomeTest.java b/mobile/android/base/tests/AboutHomeTest.java index 0eb334e3d12..8adf66552c6 100644 --- a/mobile/android/base/tests/AboutHomeTest.java +++ b/mobile/android/base/tests/AboutHomeTest.java @@ -1,24 +1,23 @@ +/* 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/. */ + package org.mozilla.gecko.tests; -import com.jayway.android.robotium.solo.Condition; -import org.mozilla.gecko.*; +import java.util.ArrayList; + +import org.mozilla.gecko.Actions; -import android.content.ContentResolver; -import android.database.Cursor; -import android.net.Uri; import android.support.v4.view.ViewPager; import android.text.TextUtils; import android.view.View; import android.view.ViewGroup; -import android.widget.GridView; -import android.widget.LinearLayout; -import android.widget.TabWidget; import android.widget.ListAdapter; import android.widget.ListView; +import android.widget.TabWidget; import android.widget.TextView; -import java.util.ArrayList; -import java.util.Arrays; +import com.jayway.android.robotium.solo.Condition; /** * This class is an extension of BaseTest that helps with interaction with about:home @@ -36,7 +35,7 @@ abstract class AboutHomeTest extends PixelTest { @Override - protected void setUp() throws Exception { + public void setUp() throws Exception { super.setUp(); if (aboutHomeTabs.size() < 4) { diff --git a/mobile/android/base/tests/BaseRobocopTest.java b/mobile/android/base/tests/BaseRobocopTest.java new file mode 100644 index 00000000000..b9378d70188 --- /dev/null +++ b/mobile/android/base/tests/BaseRobocopTest.java @@ -0,0 +1,57 @@ +/* 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/. */ + +package org.mozilla.gecko.tests; + +import java.util.Map; + +import org.mozilla.gecko.Assert; +import org.mozilla.gecko.FennecInstrumentationTestRunner; +import org.mozilla.gecko.FennecMochitestAssert; +import org.mozilla.gecko.FennecNativeDriver; +import org.mozilla.gecko.FennecTalosAssert; + +import android.app.Activity; +import android.test.ActivityInstrumentationTestCase2; + +public abstract class BaseRobocopTest extends ActivityInstrumentationTestCase2 { + public static final int TEST_MOCHITEST = 0; + public static final int TEST_TALOS = 1; + + protected static final String TARGET_PACKAGE_ID = "org.mozilla.gecko"; + protected Assert mAsserter; + protected String mLogFile; + + protected Map mConfig; + protected String mRootPath; + + public BaseRobocopTest(Class activityClass) { + super(activityClass); + } + + @SuppressWarnings("deprecation") + public BaseRobocopTest(String targetPackageId, Class activityClass) { + super(targetPackageId, activityClass); + } + + protected abstract int getTestType(); + + @Override + protected void setUp() throws Exception { + // Load config file from root path (set up by Python script). + mRootPath = FennecInstrumentationTestRunner.getFennecArguments().getString("deviceroot"); + String configFile = FennecNativeDriver.getFile(mRootPath + "/robotium.config"); + mConfig = FennecNativeDriver.convertTextToTable(configFile); + mLogFile = (String) mConfig.get("logfile"); + + // Initialize the asserter. + if (getTestType() == TEST_TALOS) { + mAsserter = new FennecTalosAssert(); + } else { + mAsserter = new FennecMochitestAssert(); + } + mAsserter.setLogFile(mLogFile); + mAsserter.setTestName(this.getClass().getName()); + } +} \ No newline at end of file diff --git a/mobile/android/base/tests/BaseTest.java b/mobile/android/base/tests/BaseTest.java index 7f70eee7b07..62528d8f783 100644 --- a/mobile/android/base/tests/BaseTest.java +++ b/mobile/android/base/tests/BaseTest.java @@ -1,63 +1,62 @@ +/* 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/. */ + package org.mozilla.gecko.tests; -import com.jayway.android.robotium.solo.Condition; -import com.jayway.android.robotium.solo.Solo; - -import org.mozilla.gecko.*; -import org.mozilla.gecko.GeckoThread.LaunchState; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import org.mozilla.gecko.Actions; +import org.mozilla.gecko.Driver; +import org.mozilla.gecko.Element; +import org.mozilla.gecko.FennecNativeActions; +import org.mozilla.gecko.FennecNativeDriver; +import org.mozilla.gecko.GeckoAppShell; +import org.mozilla.gecko.GeckoThread; +import org.mozilla.gecko.GeckoThread.LaunchState; +import org.mozilla.gecko.R; +import org.mozilla.gecko.RobocopUtils; +import org.mozilla.gecko.Tabs; import android.app.Activity; -import android.app.Instrumentation; -import android.content.ContentResolver; import android.content.ContentValues; -import android.content.ContentUris; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.res.AssetManager; import android.database.Cursor; -import android.net.Uri; import android.os.Build; import android.os.SystemClock; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; -import android.text.InputType; import android.text.TextUtils; -import android.test.ActivityInstrumentationTestCase2; import android.util.DisplayMetrics; -import android.view.inputmethod.InputMethodManager; -import android.view.KeyEvent; import android.view.View; +import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.Button; import android.widget.EditText; import android.widget.ListAdapter; -import android.widget.ListView; import android.widget.TextView; -import java.io.File; -import java.io.InputStream; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.HashMap; +import com.jayway.android.robotium.solo.Condition; +import com.jayway.android.robotium.solo.Solo; /** * A convenient base class suitable for most Robocop tests. */ -abstract class BaseTest extends ActivityInstrumentationTestCase2 { - public static final int TEST_MOCHITEST = 0; - public static final int TEST_TALOS = 1; - - private static final String TARGET_PACKAGE_ID = "org.mozilla.gecko"; +@SuppressWarnings("unchecked") +abstract class BaseTest extends BaseRobocopTest { private static final String LAUNCH_ACTIVITY_FULL_CLASSNAME = TestConstants.ANDROID_PACKAGE_NAME + ".App"; private static final int VERIFY_URL_TIMEOUT = 2000; - private static final int MAX_LIST_ATTEMPTS = 3; private static final int MAX_WAIT_ENABLED_TEXT_MS = 10000; private static final int MAX_WAIT_HOME_PAGER_HIDDEN_MS = 15000; public static final int MAX_WAIT_MS = 4500; @@ -70,11 +69,9 @@ abstract class BaseTest extends ActivityInstrumentationTestCase2 { private int mPreferenceRequestID = 0; protected Solo mSolo; protected Driver mDriver; - protected Assert mAsserter; protected Actions mActions; protected String mBaseUrl; protected String mRawBaseUrl; - private String mLogFile; protected String mProfile; public Device mDevice; protected DatabaseHelper mDatabaseHelper; @@ -104,30 +101,17 @@ abstract class BaseTest extends ActivityInstrumentationTestCase2 { super(TARGET_PACKAGE_ID, mLauncherActivityClass); } - protected abstract int getTestType(); - @Override - protected void setUp() throws Exception { - // Load config file from root path (setup by python script) - String rootPath = FennecInstrumentationTestRunner.getFennecArguments().getString("deviceroot"); - String configFile = FennecNativeDriver.getFile(rootPath + "/robotium.config"); - HashMap config = FennecNativeDriver.convertTextToTable(configFile); - mLogFile = (String)config.get("logfile"); - mBaseUrl = ((String)config.get("host")).replaceAll("(/$)", ""); - mRawBaseUrl = ((String)config.get("rawhost")).replaceAll("(/$)", ""); - // Initialize the asserter - if (getTestType() == TEST_TALOS) { - mAsserter = new FennecTalosAssert(); - } else { - mAsserter = new FennecMochitestAssert(); - } - mAsserter.setLogFile(mLogFile); - mAsserter.setTestName(this.getClass().getName()); + public void setUp() throws Exception { + super.setUp(); + // Create the intent to be used with all the important arguments. + mBaseUrl = ((String) mConfig.get("host")).replaceAll("(/$)", ""); + mRawBaseUrl = ((String) mConfig.get("rawhost")).replaceAll("(/$)", ""); Intent i = new Intent(Intent.ACTION_MAIN); - mProfile = (String)config.get("profile"); + mProfile = (String) mConfig.get("profile"); i.putExtra("args", "-no-remote -profile " + mProfile); - String envString = (String)config.get("envvars"); + String envString = (String) mConfig.get("envvars"); if (envString != "") { String[] envStrings = envString.split(","); for (int iter = 0; iter < envStrings.length; iter++) { @@ -139,7 +123,7 @@ abstract class BaseTest extends ActivityInstrumentationTestCase2 { mActivity = getActivity(); // Set up Robotium.solo and Driver objects mSolo = new Solo(getInstrumentation(), mActivity); - mDriver = new FennecNativeDriver(mActivity, mSolo, rootPath); + mDriver = new FennecNativeDriver(mActivity, mSolo, mRootPath); mActions = new FennecNativeActions(mActivity, mSolo, getInstrumentation(), mAsserter); mDevice = new Device(); mDatabaseHelper = new DatabaseHelper(mActivity, mAsserter); @@ -333,7 +317,6 @@ abstract class BaseTest extends ActivityInstrumentationTestCase2 { public boolean test(); } - @SuppressWarnings({"unchecked", "non-varargs"}) public void SqliteCompare(String dbName, String sqlCommand, ContentValues[] cvs) { File profile = new File(mProfile); String dbPath = new File(profile, dbName).getPath(); @@ -342,27 +325,6 @@ abstract class BaseTest extends ActivityInstrumentationTestCase2 { SqliteCompare(c, cvs); } - private boolean CursorMatches(Cursor c, String[] columns, ContentValues cv) { - for (int i = 0; i < columns.length; i++) { - String column = columns[i]; - if (cv.containsKey(column)) { - mAsserter.info("Comparing", "Column values for: " + column); - Object value = cv.get(column); - if (value == null) { - if (!c.isNull(i)) { - return false; - } - } else { - if (c.isNull(i) || !value.toString().equals(c.getString(i))) { - return false; - } - } - } - } - return true; - } - - @SuppressWarnings({"unchecked", "non-varargs"}) public void SqliteCompare(Cursor c, ContentValues[] cvs) { mAsserter.is(c.getCount(), cvs.length, "List is correct length"); if (c.moveToFirst()) { @@ -374,7 +336,7 @@ abstract class BaseTest extends ActivityInstrumentationTestCase2 { } } mAsserter.is(found, true, "Password was found"); - } while(c.moveToNext()); + } while (c.moveToNext()); } } diff --git a/mobile/android/base/tests/ContentProviderTest.java b/mobile/android/base/tests/ContentProviderTest.java index fd670155310..3310ee40fb1 100644 --- a/mobile/android/base/tests/ContentProviderTest.java +++ b/mobile/android/base/tests/ContentProviderTest.java @@ -1,3 +1,7 @@ +/* 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/. */ + package org.mozilla.gecko.tests; import android.content.ContentProvider; @@ -208,7 +212,7 @@ abstract class ContentProviderTest extends BaseTest { mResolver.addProvider(mProviderAuthority, mProvider); } - public Uri appendUriParam(Uri uri, String param, String value) { + public static Uri appendUriParam(Uri uri, String param, String value) { return uri.buildUpon().appendQueryParameter(param, value).build(); } diff --git a/mobile/android/base/tests/testBrowserProviderPerf.java b/mobile/android/base/tests/testBrowserProviderPerf.java index 660805b2a69..63085392394 100644 --- a/mobile/android/base/tests/testBrowserProviderPerf.java +++ b/mobile/android/base/tests/testBrowserProviderPerf.java @@ -1,22 +1,47 @@ +/* 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/. */ + package org.mozilla.gecko.tests; +import java.io.File; +import java.util.Random; +import java.util.UUID; + +import org.mozilla.gecko.db.BrowserContract; +import org.mozilla.gecko.db.BrowserProvider; +import org.mozilla.gecko.db.LocalBrowserDB; +import org.mozilla.gecko.util.FileUtils; + +import android.app.Activity; +import android.content.ContentProvider; +import android.content.ContentProviderClient; +import android.content.ContentResolver; import android.content.ContentValues; import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.net.Uri; import android.os.SystemClock; +import android.util.Log; -import java.util.UUID; -import java.util.Random; - -import org.mozilla.gecko.GeckoProfile; -import org.mozilla.gecko.db.BrowserContract; -import org.mozilla.gecko.db.BrowserDB; -import org.mozilla.gecko.db.BrowserProvider; - -/* - * This test is meant to exercise the performance of Fennec's - * history and bookmarks content provider. +/** + * This test is meant to exercise the performance of Fennec's history and + * bookmarks content provider. + * + * It does not extend ContentProviderTest because that class is unable to + * accurately assess the performance of the ContentProvider -- it's a second + * instance of a class that's only supposed to exist once, wrapped in a bunch of + * junk. + * + * Instead, we directly use the existing ContentProvider, accessing a new + * profile directory that we initialize via BrowserDB. */ -public class testBrowserProviderPerf extends ContentProviderTest { +@SuppressWarnings("unchecked") +public class testBrowserProviderPerf extends BaseRobocopTest { + private static final String LAUNCH_ACTIVITY_FULL_CLASSNAME = TestConstants.ANDROID_PACKAGE_NAME + ".App"; + + private static Class mLauncherActivityClass; + private final int NUMBER_OF_BASIC_HISTORY_URLS = 10000; private final int NUMBER_OF_BASIC_BOOKMARK_URLS = 500; private final int NUMBER_OF_COMBINED_URLS = 500; @@ -25,13 +50,30 @@ public class testBrowserProviderPerf extends ContentProviderTest { private final int BATCH_SIZE = 500; // Include spaces in prefix to test performance querying with - // multiple constraint words + // multiple constraint words. private final String KNOWN_PREFIX = "my mozilla test "; private Random mGenerator; private final String MOBILE_FOLDER_GUID = "mobile"; private long mMobileFolderId; + private ContentResolver mResolver; + private String mProfile; + private Uri mHistoryURI; + private Uri mBookmarksURI; + private Uri mFaviconsURI; + + static { + try { + mLauncherActivityClass = (Class) Class.forName(LAUNCH_ACTIVITY_FULL_CLASSNAME); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + public testBrowserProviderPerf() { + super(TARGET_PACKAGE_ID, mLauncherActivityClass); + } @Override protected int getTestType() { @@ -39,7 +81,7 @@ public class testBrowserProviderPerf extends ContentProviderTest { } private void loadMobileFolderId() throws Exception { - Cursor c = mProvider.query(BrowserContract.Bookmarks.CONTENT_URI, null, + Cursor c = mResolver.query(mBookmarksURI, null, BrowserContract.Bookmarks.GUID + " = ?", new String[] { MOBILE_FOLDER_GUID }, null); @@ -121,7 +163,7 @@ public class testBrowserProviderPerf extends ContentProviderTest { } private void addTonsOfUrls() throws Exception { - // Create some random bookmark entries + // Create some random bookmark entries. ContentValues[] bookmarkEntries = new ContentValues[BATCH_SIZE]; for (int i = 0; i < NUMBER_OF_BASIC_BOOKMARK_URLS / BATCH_SIZE; i++) { @@ -131,10 +173,10 @@ public class testBrowserProviderPerf extends ContentProviderTest { bookmarkEntries[j] = createRandomBookmarkEntry(); } - mProvider.bulkInsert(BrowserContract.Bookmarks.CONTENT_URI, bookmarkEntries); + mResolver.bulkInsert(mBookmarksURI, bookmarkEntries); } - // Create some random history entries + // Create some random history entries. ContentValues[] historyEntries = new ContentValues[BATCH_SIZE]; ContentValues[] faviconEntries = new ContentValues[BATCH_SIZE]; @@ -147,12 +189,12 @@ public class testBrowserProviderPerf extends ContentProviderTest { faviconEntries[j] = createFaviconEntryWithUrl(historyEntries[j].getAsString(BrowserContract.History.URL)); } - mProvider.bulkInsert(BrowserContract.History.CONTENT_URI, historyEntries); - mProvider.bulkInsert(BrowserContract.Favicons.CONTENT_URI, faviconEntries); + mResolver.bulkInsert(mHistoryURI, historyEntries); + mResolver.bulkInsert(mFaviconsURI, faviconEntries); } - // Create random bookmark/history entries with the same url + // Create random bookmark/history entries with the same URL. for (int i = 0; i < NUMBER_OF_COMBINED_URLS / BATCH_SIZE; i++) { bookmarkEntries = new ContentValues[BATCH_SIZE]; historyEntries = new ContentValues[BATCH_SIZE]; @@ -164,12 +206,12 @@ public class testBrowserProviderPerf extends ContentProviderTest { faviconEntries[j] = createFaviconEntryWithUrl(url); } - mProvider.bulkInsert(BrowserContract.Bookmarks.CONTENT_URI, bookmarkEntries); - mProvider.bulkInsert(BrowserContract.History.CONTENT_URI, historyEntries); - mProvider.bulkInsert(BrowserContract.Favicons.CONTENT_URI, faviconEntries); + mResolver.bulkInsert(mBookmarksURI, bookmarkEntries); + mResolver.bulkInsert(mHistoryURI, historyEntries); + mResolver.bulkInsert(mFaviconsURI, faviconEntries); } - // Create some history entries with a known prefix + // Create some history entries with a known prefix. historyEntries = new ContentValues[NUMBER_OF_KNOWN_URLS]; faviconEntries = new ContentValues[NUMBER_OF_KNOWN_URLS]; for (int i = 0; i < NUMBER_OF_KNOWN_URLS; i++) { @@ -177,34 +219,112 @@ public class testBrowserProviderPerf extends ContentProviderTest { faviconEntries[i] = createFaviconEntryWithUrl(historyEntries[i].getAsString(BrowserContract.History.URL)); } - mProvider.bulkInsert(BrowserContract.History.CONTENT_URI, historyEntries); - mProvider.bulkInsert(BrowserContract.Favicons.CONTENT_URI, faviconEntries); + mResolver.bulkInsert(mHistoryURI, historyEntries); + mResolver.bulkInsert(mFaviconsURI, faviconEntries); } @Override public void setUp() throws Exception { - super.setUp(sBrowserProviderCallable, BrowserContract.AUTHORITY, "browser.db"); + super.setUp(); + + mProfile = "prof" + System.currentTimeMillis(); + + mHistoryURI = prepUri(BrowserContract.History.CONTENT_URI); + mBookmarksURI = prepUri(BrowserContract.Bookmarks.CONTENT_URI); + mFaviconsURI = prepUri(BrowserContract.Favicons.CONTENT_URI); + + mResolver = getActivity().getApplicationContext().getContentResolver(); mGenerator = new Random(19580427); } - public void testBrowserProviderPerf() throws Exception { - BrowserDB.initialize(GeckoProfile.DEFAULT_PROFILE); + @Override + public void tearDown() { + final ContentProviderClient client = mResolver.acquireContentProviderClient(mBookmarksURI); + try { + final ContentProvider cp = client.getLocalContentProvider(); + final BrowserProvider bp = ((BrowserProvider) cp); + // This will be the DB we were just testing. + final SQLiteDatabase db = bp.getWritableDatabaseForTesting(mBookmarksURI); + try { + db.close(); + } catch (Throwable e) { + // Nothing we can do. + } + } finally { + try { + client.release(); + } catch (Throwable e) { + // Still go ahead and try to delete the profile. + } + + try { + FileUtils.delTree(new File(mProfile), null, true); + } catch (Exception e) { + Log.w("GeckoTest", "Unable to delete profile " + mProfile, e); + } + } + } + + public Uri prepUri(Uri uri) { + return uri.buildUpon() + .appendQueryParameter(BrowserContract.PARAM_PROFILE, mProfile) + .appendQueryParameter(BrowserContract.PARAM_IS_SYNC, "1") // So we don't trigger a sync. + .build(); + } + + /** + * This method: + * + * * Adds a bunch of test data via the ContentProvider API. + * * Runs a single query against that test data via BrowserDB. + * * Reports timing for Talos. + */ + public void testBrowserProviderQueryPerf() throws Exception { + // We add at least this many results. + final int limit = 100; + + // Make sure we're querying the right profile. + final LocalBrowserDB db = new LocalBrowserDB(mProfile); + + final Cursor before = db.filter(mResolver, KNOWN_PREFIX, limit); + try { + mAsserter.is(before.getCount(), 0, "Starts empty"); + } finally { + before.close(); + } + + // Add data. loadMobileFolderId(); addTonsOfUrls(); - long start = SystemClock.uptimeMillis(); + // Wait for a little while after inserting data. We do this because + // this test launches about:home, and Top Sites watches for DB changes. + // We don't have a good way for it to only watch changes related to + // its current profile, nor is it convenient for us to launch a different + // activity that doesn't depend on the DB. + // We can fix this by: + // * Adjusting the provider interface to allow a "don't notify" param. + // * Adjusting the interface schema to include the profile in the path, + // and only observe the correct path. + // * Launching a different activity. + Thread.sleep(5000); - final Cursor c = BrowserDB.filter(mResolver, KNOWN_PREFIX, 100); - c.getCount(); // ensure query is not lazy loaded + // Time the query. + final long start = SystemClock.uptimeMillis(); + final Cursor c = db.filter(mResolver, KNOWN_PREFIX, limit); - long end = SystemClock.uptimeMillis(); + try { + final int count = c.getCount(); + final long end = SystemClock.uptimeMillis(); - mAsserter.dumpLog("__start_report" + Long.toString(end - start) + "__end_report"); - mAsserter.dumpLog("__startTimestamp" + Long.toString(end - start) + "__endTimestamp"); - - c.close(); + mAsserter.is(count, limit, "Retrieved results"); + mAsserter.dumpLog("Results: " + count); + mAsserter.dumpLog("__start_report" + Long.toString(end - start) + "__end_report"); + mAsserter.dumpLog("__startTimestamp" + Long.toString(end - start) + "__endTimestamp"); + } finally { + c.close(); + } } - } diff --git a/mobile/android/base/tests/testReadingListProvider.java b/mobile/android/base/tests/testReadingListProvider.java index 9b16302d696..222ae1d502f 100644 --- a/mobile/android/base/tests/testReadingListProvider.java +++ b/mobile/android/base/tests/testReadingListProvider.java @@ -1,3 +1,7 @@ +/* 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/. */ + package org.mozilla.gecko.tests; import java.util.HashSet; @@ -7,7 +11,6 @@ import java.util.concurrent.Callable; import org.mozilla.gecko.db.BrowserContract; import org.mozilla.gecko.db.BrowserContract.ReadingListItems; import org.mozilla.gecko.db.ReadingListProvider; -import org.mozilla.gecko.db.TransactionalProvider; import android.content.ContentProvider; import android.content.ContentUris; @@ -68,12 +71,13 @@ public class testReadingListProvider extends ContentProviderTest { } } - public void testReadingListProvider() throws Exception { + public void testReadingListProviderTests() throws Exception { for (Runnable test : mTests) { setTestName(test.getClass().getSimpleName()); ensureEmptyDatabase(); test.run(); } + // Ensure browser initialization is complete before completing test, // so that the minidumps directory is consistently created. blockForGeckoReady(); diff --git a/mobile/android/base/toolbar/ToolbarEditText.java b/mobile/android/base/toolbar/ToolbarEditText.java index f0a7c1e5c48..dc43e12de1e 100644 --- a/mobile/android/base/toolbar/ToolbarEditText.java +++ b/mobile/android/base/toolbar/ToolbarEditText.java @@ -110,6 +110,7 @@ public class ToolbarEditText extends CustomEditText super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); if (gainFocus) { + resetAutocompleteState(); return; } @@ -152,6 +153,11 @@ public class ToolbarEditText extends CustomEditText updateTextTypeFromText(getText().toString()); } + private void resetAutocompleteState() { + mAutoCompleteResult = ""; + mAutoCompletePrefix = null; + } + private void updateKeyboardInputType() { // If the user enters a space, then we know they are entering // search terms, not a URL. We can then switch to text mode so, diff --git a/mobile/android/base/util/FileUtils.java b/mobile/android/base/util/FileUtils.java index 25a26e541b7..a89ac90b496 100644 --- a/mobile/android/base/util/FileUtils.java +++ b/mobile/android/base/util/FileUtils.java @@ -10,6 +10,8 @@ import java.io.File; import java.io.IOException; import java.io.FilenameFilter; +import org.mozilla.gecko.mozglue.RobocopTarget; + public class FileUtils { private static final String LOGTAG= "GeckoFileUtils"; /* @@ -38,6 +40,7 @@ public class FileUtils { } } + @RobocopTarget public static void delTree(File dir, FilenameFilter filter, boolean recurse) { String[] files = null; 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/mobile/android/services/manifests/FxAccountAndroidManifest_activities.xml.in b/mobile/android/services/manifests/FxAccountAndroidManifest_activities.xml.in index 816516884a1..d0512f41fa7 100644 --- a/mobile/android/services/manifests/FxAccountAndroidManifest_activities.xml.in +++ b/mobile/android/services/manifests/FxAccountAndroidManifest_activities.xml.in @@ -74,3 +74,11 @@ + + + + + + + diff --git a/mobile/android/services/manifests/SyncAndroidManifest_activities.xml.in b/mobile/android/services/manifests/SyncAndroidManifest_activities.xml.in index 245136e1116..5a35c272742 100644 --- a/mobile/android/services/manifests/SyncAndroidManifest_activities.xml.in +++ b/mobile/android/services/manifests/SyncAndroidManifest_activities.xml.in @@ -61,7 +61,8 @@ - + + 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/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index 06ee65566ba..b37ad139d74 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -565,9 +565,6 @@ pref("devtools.debugger.prompt-connection", true); // Block tools from seeing / interacting with certified apps pref("devtools.debugger.forbid-certified-apps", true); -// Disable add-on debugging -pref("devtools.debugger.addon-enabled", false); - // DevTools default color unit pref("devtools.defaultColorUnit", "hex"); 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" - " + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/toolkit/themes/linux/global/jar.mn b/toolkit/themes/linux/global/jar.mn index e5cf359d18c..b0c9d32e567 100644 --- a/toolkit/themes/linux/global/jar.mn +++ b/toolkit/themes/linux/global/jar.mn @@ -43,6 +43,7 @@ toolkit.jar: + skin/classic/global/icons/autoscroll.png (icons/autoscroll.png) + skin/classic/global/icons/blacklist_favicon.png (icons/blacklist_favicon.png) + skin/classic/global/icons/blacklist_large.png (icons/blacklist_large.png) ++ skin/classic/global/icons/close.svg (icons/close.svg) + skin/classic/global/icons/find.png (icons/find.png) + skin/classic/global/icons/loading_16.png (icons/loading_16.png) + skin/classic/global/icons/panelarrow-horizontal.svg (icons/panelarrow-horizontal.svg) diff --git a/toolkit/themes/linux/global/notification.css b/toolkit/themes/linux/global/notification.css index caea875c2c2..f75d3415159 100644 --- a/toolkit/themes/linux/global/notification.css +++ b/toolkit/themes/linux/global/notification.css @@ -52,9 +52,11 @@ notification[type="critical"] { } .messageCloseButton { - list-style-image: url("moz-icon://stock/gtk-close?size=menu"); - margin-top: 0; - margin-bottom: 0; + -moz-appearance: none; + width: 16px; + height: 16px; + padding-left: 11px; + padding-right: 11px; } /* Popup notification */ @@ -74,7 +76,3 @@ notification[type="critical"] { .popup-notification-button-container { margin-top: 17px; } - -.popup-notification-closeitem { - list-style-image: url("moz-icon://stock/gtk-close?size=menu"); -} diff --git a/toolkit/themes/linux/mozapps/extensions/category-experiments.png b/toolkit/themes/linux/mozapps/extensions/category-experiments.png new file mode 100644 index 00000000000..a9d00545ef3 Binary files /dev/null and b/toolkit/themes/linux/mozapps/extensions/category-experiments.png differ diff --git a/toolkit/themes/linux/mozapps/extensions/experimentGeneric.png b/toolkit/themes/linux/mozapps/extensions/experimentGeneric.png new file mode 100644 index 00000000000..a9d00545ef3 Binary files /dev/null and b/toolkit/themes/linux/mozapps/extensions/experimentGeneric.png differ diff --git a/toolkit/themes/linux/mozapps/extensions/extensions.css b/toolkit/themes/linux/mozapps/extensions/extensions.css index aaf7f3d171d..72729290582 100644 --- a/toolkit/themes/linux/mozapps/extensions/extensions.css +++ b/toolkit/themes/linux/mozapps/extensions/extensions.css @@ -226,6 +226,9 @@ #category-dictionary > .category-icon { list-style-image: url("chrome://mozapps/skin/extensions/category-dictionaries.png"); } +#category-experiment > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-experiments.png"); +} #category-availableUpdates > .category-icon { list-style-image: url("chrome://mozapps/skin/extensions/category-available.png"); } @@ -417,6 +420,10 @@ list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png"); } +.addon-view[type="experiment"] .icon { + list-style-image: url("chrome://mozapps/skin/extensions/experimentGeneric.png"); +} + .name-container { font-size: 150%; margin-bottom: 0; diff --git a/toolkit/themes/linux/mozapps/jar.mn b/toolkit/themes/linux/mozapps/jar.mn index 2b795107672..b8deb507468 100644 --- a/toolkit/themes/linux/mozapps/jar.mn +++ b/toolkit/themes/linux/mozapps/jar.mn @@ -15,12 +15,14 @@ toolkit.jar: + skin/classic/mozapps/extensions/category-plugins.png (extensions/category-plugins.png) + skin/classic/mozapps/extensions/category-service.png (extensions/category-service.png) + skin/classic/mozapps/extensions/category-dictionaries.png (extensions/category-dictionaries.png) ++ skin/classic/mozapps/extensions/category-experiments.png (extensions/category-experiments.png) + skin/classic/mozapps/extensions/category-recent.png (extensions/category-recent.png) + skin/classic/mozapps/extensions/category-available.png (extensions/category-available.png) + skin/classic/mozapps/extensions/extensionGeneric.png (extensions/extensionGeneric.png) + skin/classic/mozapps/extensions/extensionGeneric-16.png (extensions/extensionGeneric-16.png) + skin/classic/mozapps/extensions/dictionaryGeneric.png (extensions/dictionaryGeneric.png) + skin/classic/mozapps/extensions/dictionaryGeneric-16.png (extensions/dictionaryGeneric-16.png) ++ skin/classic/mozapps/extensions/experimentGeneric.png (extensions/experimentGeneric.png) + skin/classic/mozapps/extensions/themeGeneric.png (extensions/themeGeneric.png) + skin/classic/mozapps/extensions/themeGeneric-16.png (extensions/themeGeneric-16.png) + skin/classic/mozapps/extensions/localeGeneric.png (extensions/localeGeneric.png) diff --git a/toolkit/themes/osx/global/dirListing/dirListing.css b/toolkit/themes/osx/global/dirListing/dirListing.css index d89752db13c..563c1112978 100644 --- a/toolkit/themes/osx/global/dirListing/dirListing.css +++ b/toolkit/themes/osx/global/dirListing/dirListing.css @@ -77,7 +77,7 @@ th:hover > a { text-decoration: underline; } -tbody > tr:hover { +body > table > tbody > tr:hover { outline: 1px solid ThreeDLightShadow; -moz-outline-radius: .3em; } diff --git a/toolkit/themes/osx/mozapps/extensions/category-experiments.png b/toolkit/themes/osx/mozapps/extensions/category-experiments.png new file mode 100644 index 00000000000..a9d00545ef3 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/category-experiments.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/experimentGeneric.png b/toolkit/themes/osx/mozapps/extensions/experimentGeneric.png new file mode 100644 index 00000000000..a9d00545ef3 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/experimentGeneric.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/extensions.css b/toolkit/themes/osx/mozapps/extensions/extensions.css index 89a02dd70c3..c4326c5f83d 100644 --- a/toolkit/themes/osx/mozapps/extensions/extensions.css +++ b/toolkit/themes/osx/mozapps/extensions/extensions.css @@ -259,6 +259,9 @@ #category-dictionary > .category-icon { list-style-image: url("chrome://mozapps/skin/extensions/category-dictionaries.png"); } +#category-experiment > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-experiments.png"); +} #category-availableUpdates > .category-icon { list-style-image: url("chrome://mozapps/skin/extensions/category-available.png"); } @@ -483,6 +486,10 @@ list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png"); } +.addon-view[type="experiment"] .icon { + list-style-image: url("chrome://mozapps/skin/extensions/experimentGeneric.png"); +} + .name-container { font-size: 150%; margin-bottom: 0; diff --git a/toolkit/themes/osx/mozapps/jar.mn b/toolkit/themes/osx/mozapps/jar.mn index 425b4571552..2336c2e01c6 100644 --- a/toolkit/themes/osx/mozapps/jar.mn +++ b/toolkit/themes/osx/mozapps/jar.mn @@ -17,6 +17,7 @@ toolkit.jar: skin/classic/mozapps/extensions/category-plugins.png (extensions/category-plugins.png) skin/classic/mozapps/extensions/category-service.png (extensions/category-service.png) skin/classic/mozapps/extensions/category-dictionaries.png (extensions/category-dictionaries.png) + skin/classic/mozapps/extensions/category-experiments.png (extensions/category-experiments.png) skin/classic/mozapps/extensions/category-recent.png (extensions/category-recent.png) skin/classic/mozapps/extensions/category-available.png (extensions/category-available.png) skin/classic/mozapps/extensions/discover-logo.png (extensions/discover-logo.png) @@ -26,6 +27,7 @@ toolkit.jar: skin/classic/mozapps/extensions/themeGeneric-16.png (extensions/themeGeneric-16.png) skin/classic/mozapps/extensions/dictionaryGeneric.png (extensions/dictionaryGeneric.png) skin/classic/mozapps/extensions/dictionaryGeneric-16.png (extensions/dictionaryGeneric-16.png) + skin/classic/mozapps/extensions/experimentGeneric.png (extensions/experimentGeneric.png) skin/classic/mozapps/extensions/localeGeneric.png (extensions/localeGeneric.png) skin/classic/mozapps/extensions/rating-won.png (extensions/rating-won.png) skin/classic/mozapps/extensions/rating-not-won.png (extensions/rating-not-won.png) diff --git a/toolkit/themes/windows/global/dirListing/dirListing.css b/toolkit/themes/windows/global/dirListing/dirListing.css index 35dab890a87..7b6e7448d11 100644 --- a/toolkit/themes/windows/global/dirListing/dirListing.css +++ b/toolkit/themes/windows/global/dirListing/dirListing.css @@ -77,7 +77,7 @@ th:hover > a { text-decoration: underline; } -tbody > tr:hover { +body > table > tbody > tr:hover { outline: 1px solid ThreeDLightShadow; -moz-outline-radius: .3em; } diff --git a/toolkit/themes/windows/mozapps/extensions/category-experiments-aero.png b/toolkit/themes/windows/mozapps/extensions/category-experiments-aero.png new file mode 100644 index 00000000000..a9d00545ef3 Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/category-experiments-aero.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/category-experiments.png b/toolkit/themes/windows/mozapps/extensions/category-experiments.png new file mode 100644 index 00000000000..a9d00545ef3 Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/category-experiments.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/experimentGeneric-aero.png b/toolkit/themes/windows/mozapps/extensions/experimentGeneric-aero.png new file mode 100644 index 00000000000..a9d00545ef3 Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/experimentGeneric-aero.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/experimentGeneric.png b/toolkit/themes/windows/mozapps/extensions/experimentGeneric.png new file mode 100644 index 00000000000..a9d00545ef3 Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/experimentGeneric.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/extensions.css b/toolkit/themes/windows/mozapps/extensions/extensions.css index ccbd32bfd4f..78a140b4a0a 100644 --- a/toolkit/themes/windows/mozapps/extensions/extensions.css +++ b/toolkit/themes/windows/mozapps/extensions/extensions.css @@ -271,6 +271,9 @@ #category-dictionary > .category-icon { list-style-image: url("chrome://mozapps/skin/extensions/category-dictionaries.png"); } +#category-experiment > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-experiments.png"); +} #category-availableUpdates > .category-icon { list-style-image: url("chrome://mozapps/skin/extensions/category-available.png"); } @@ -485,6 +488,10 @@ list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png"); } +.addon-view[type="experiment"] .icon { + list-style-image: url("chrome://mozapps/skin/extensions/experimentGeneric.png"); +} + .name-container { font-size: 150%; font-weight: bold; diff --git a/toolkit/themes/windows/mozapps/jar.mn b/toolkit/themes/windows/mozapps/jar.mn index 286ea6d52a1..d0bd5ed24eb 100644 --- a/toolkit/themes/windows/mozapps/jar.mn +++ b/toolkit/themes/windows/mozapps/jar.mn @@ -26,6 +26,7 @@ toolkit.jar: skin/classic/mozapps/extensions/category-plugins.png (extensions/category-plugins.png) skin/classic/mozapps/extensions/category-service.png (extensions/category-service.png) skin/classic/mozapps/extensions/category-dictionaries.png (extensions/category-dictionaries.png) + skin/classic/mozapps/extensions/category-experiments.png (extensions/category-experiments.png) skin/classic/mozapps/extensions/category-recent.png (extensions/category-recent.png) skin/classic/mozapps/extensions/category-available.png (extensions/category-available.png) skin/classic/mozapps/extensions/discover-logo.png (extensions/discover-logo.png) @@ -35,6 +36,7 @@ toolkit.jar: skin/classic/mozapps/extensions/themeGeneric-16.png (extensions/themeGeneric-16.png) skin/classic/mozapps/extensions/dictionaryGeneric.png (extensions/dictionaryGeneric.png) skin/classic/mozapps/extensions/dictionaryGeneric-16.png (extensions/dictionaryGeneric-16.png) + skin/classic/mozapps/extensions/experimentGeneric.png (extensions/experimentGeneric.png) skin/classic/mozapps/extensions/localeGeneric.png (extensions/localeGeneric.png) skin/classic/mozapps/extensions/rating-won.png (extensions/rating-won.png) skin/classic/mozapps/extensions/rating-not-won.png (extensions/rating-not-won.png) @@ -107,6 +109,7 @@ toolkit.jar: skin/classic/aero/mozapps/extensions/category-plugins.png (extensions/category-plugins-aero.png) skin/classic/aero/mozapps/extensions/category-service.png (extensions/category-service.png) skin/classic/aero/mozapps/extensions/category-dictionaries.png (extensions/category-dictionaries-aero.png) + skin/classic/aero/mozapps/extensions/category-experiments.png (extensions/category-experiments-aero.png) skin/classic/aero/mozapps/extensions/category-recent.png (extensions/category-recent-aero.png) skin/classic/aero/mozapps/extensions/category-available.png (extensions/category-available-aero.png) skin/classic/aero/mozapps/extensions/discover-logo.png (extensions/discover-logo.png) @@ -117,6 +120,7 @@ toolkit.jar: skin/classic/aero/mozapps/extensions/dictionaryGeneric.png (extensions/dictionaryGeneric-aero.png) skin/classic/aero/mozapps/extensions/dictionaryGeneric-16.png (extensions/dictionaryGeneric-16-aero.png) skin/classic/aero/mozapps/extensions/localeGeneric.png (extensions/localeGeneric-aero.png) + skin/classic/aero/mozapps/extensions/experimentGeneric.png (extensions/experimentGeneric-aero.png) skin/classic/aero/mozapps/extensions/rating-won.png (extensions/rating-won.png) skin/classic/aero/mozapps/extensions/rating-not-won.png (extensions/rating-not-won.png) skin/classic/aero/mozapps/extensions/cancel.png (extensions/cancel.png) diff --git a/toolkit/webapps/tests/app.sjs b/toolkit/webapps/tests/app.sjs new file mode 100644 index 00000000000..6b07fe54dfd --- /dev/null +++ b/toolkit/webapps/tests/app.sjs @@ -0,0 +1,33 @@ +function getQuery(request) { + let query = {}; + + request.queryString.split('&').forEach(function(val) { + let [name, value] = val.split('='); + query[name] = unescape(value); + }); + + return query; +} + +function handleRequest(request, response) { + response.setHeader("Cache-Control", "no-cache", false); + + let query = getQuery(request); + + if ("appreq" in query) { + response.setHeader("Content-Type", "text/plain", false); + response.write("Hello world!"); + + setState("appreq", "done"); + + return; + } + + if ("testreq" in query) { + response.setHeader("Content-Type", "text/plain", false); + + response.write(getState("appreq")); + + return; + } +} diff --git a/toolkit/webapps/tests/chrome.ini b/toolkit/webapps/tests/chrome.ini index 92219173d6c..cfd283edfca 100644 --- a/toolkit/webapps/tests/chrome.ini +++ b/toolkit/webapps/tests/chrome.ini @@ -1,8 +1,15 @@ [DEFAULT] support-files = head.js + app.sjs + data/app/index.html + data/app/manifest.webapp [test_hosted.xul] skip-if = os == "mac" [test_packaged.xul] skip-if = os == "mac" +[test_hosted_launch.xul] +skip-if = os == "mac" || asan +[test_packaged_launch.xul] +skip-if = os == "mac" || asan diff --git a/toolkit/webapps/tests/data/app/index.html b/toolkit/webapps/tests/data/app/index.html new file mode 100644 index 00000000000..12c6881c245 --- /dev/null +++ b/toolkit/webapps/tests/data/app/index.html @@ -0,0 +1,10 @@ + + + +Test app + + +Test app: + + + diff --git a/toolkit/webapps/tests/data/app/manifest.webapp b/toolkit/webapps/tests/data/app/manifest.webapp new file mode 100644 index 00000000000..22dedf95279 --- /dev/null +++ b/toolkit/webapps/tests/data/app/manifest.webapp @@ -0,0 +1,5 @@ +{ + "name": "Test app", + "description": "A test application", + "launch_path": "/index.html" +} diff --git a/toolkit/webapps/tests/head.js b/toolkit/webapps/tests/head.js index d6840163c63..5ff308f47a6 100644 --- a/toolkit/webapps/tests/head.js +++ b/toolkit/webapps/tests/head.js @@ -48,3 +48,10 @@ function wait(time) { return deferred.promise; } + +// Helper to create a nsIFile from a set of path components +function getFile() { + let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); + file.initWithPath(OS.Path.join.apply(OS.Path, arguments)); + return file; +} diff --git a/toolkit/webapps/tests/test_hosted.xul b/toolkit/webapps/tests/test_hosted.xul index 1132a2f5430..1382e46a0ac 100644 --- a/toolkit/webapps/tests/test_hosted.xul +++ b/toolkit/webapps/tests/test_hosted.xul @@ -249,6 +249,7 @@ Task.spawn(function() { } ok(true, "App launchable"); ok((yield checkFiles(installedFiles)), "Files correctly written"); + is(WebappOSUtils.getInstallPath(app), installPath, "getInstallPath == installPath"); let stat = yield OS.File.stat(installPath); let installTime = stat.lastModificationDate; diff --git a/toolkit/webapps/tests/test_hosted_launch.xul b/toolkit/webapps/tests/test_hosted_launch.xul new file mode 100644 index 00000000000..65bb0cde895 --- /dev/null +++ b/toolkit/webapps/tests/test_hosted_launch.xul @@ -0,0 +1,226 @@ + + + + + + + + diff --git a/toolkit/webapps/tests/test_packaged.xul b/toolkit/webapps/tests/test_packaged.xul index 83074f9ea95..bfa2cc72e20 100644 --- a/toolkit/webapps/tests/test_packaged.xul +++ b/toolkit/webapps/tests/test_packaged.xul @@ -267,6 +267,7 @@ Task.spawn(function() { } ok(true, "App launchable"); ok((yield checkFiles(installedFiles)), "Files correctly written"); + is(WebappOSUtils.getInstallPath(app), installPath, "getInstallPath == installPath"); let stat = yield OS.File.stat(installPath); let installTime = stat.lastModificationDate; diff --git a/toolkit/webapps/tests/test_packaged_launch.xul b/toolkit/webapps/tests/test_packaged_launch.xul new file mode 100644 index 00000000000..bfa1fe956ef --- /dev/null +++ b/toolkit/webapps/tests/test_packaged_launch.xul @@ -0,0 +1,256 @@ + + + + + + + + + diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index aff99906cb5..160d547a2af 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -617,13 +617,13 @@ NS_INTERFACE_MAP_BEGIN(nsXULAppInfo) XRE_GetProcessType() == GeckoProcessType_Content) NS_INTERFACE_MAP_END -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) nsXULAppInfo::AddRef() { return 1; } -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) nsXULAppInfo::Release() { return 1; diff --git a/toolkit/xre/nsXREDirProvider.cpp b/toolkit/xre/nsXREDirProvider.cpp index 1b82b4c9ee2..d727046e58b 100644 --- a/toolkit/xre/nsXREDirProvider.cpp +++ b/toolkit/xre/nsXREDirProvider.cpp @@ -164,13 +164,13 @@ NS_IMPL_QUERY_INTERFACE3(nsXREDirProvider, nsIDirectoryServiceProvider2, nsIProfileStartup) -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) nsXREDirProvider::AddRef() { return 1; } -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) nsXREDirProvider::Release() { return 0; diff --git a/toolkit/xre/nsXREDirProvider.h b/toolkit/xre/nsXREDirProvider.h index ba9bd999972..4a9f9a0b838 100644 --- a/toolkit/xre/nsXREDirProvider.h +++ b/toolkit/xre/nsXREDirProvider.h @@ -20,8 +20,8 @@ class nsXREDirProvider MOZ_FINAL : public nsIDirectoryServiceProvider2, public: // we use a custom isupports implementation (no refcount) NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); - NS_IMETHOD_(nsrefcnt) AddRef(void); - NS_IMETHOD_(nsrefcnt) Release(void); + NS_IMETHOD_(MozExternalRefCountType) AddRef(void); + NS_IMETHOD_(MozExternalRefCountType) Release(void); NS_DECL_NSIDIRECTORYSERVICEPROVIDER NS_DECL_NSIDIRECTORYSERVICEPROVIDER2 diff --git a/tools/profiler/EHABIStackWalk.cpp b/tools/profiler/EHABIStackWalk.cpp index ef378db9042..e11c499cc9f 100644 --- a/tools/profiler/EHABIStackWalk.cpp +++ b/tools/profiler/EHABIStackWalk.cpp @@ -163,6 +163,9 @@ private: class EHInterp { public: + // Note that stackLimit is exclusive and stackBase is inclusive + // (i.e, stackLimit < SP <= stackBase), following the convention + // set by the AAPCS spec. EHInterp(EHState &aState, const EHEntry *aEntry, uint32_t aStackLimit, uint32_t aStackBase) : mState(aState), @@ -294,10 +297,11 @@ private: }; -bool EHState::unwind(const EHEntry *aEntry, const void *stackLimit) { - EHInterp interp(*this, aEntry, mRegs[R_SP] - 4, - reinterpret_cast(stackLimit)); - +bool EHState::unwind(const EHEntry *aEntry, const void *stackBasePtr) { + // The unwinding program cannot set SP to less than the initial value. + uint32_t stackLimit = mRegs[R_SP] - 4; + uint32_t stackBase = reinterpret_cast(stackBasePtr); + EHInterp interp(*this, aEntry, stackLimit, stackBase); return interp.unwind(); } diff --git a/tools/profiler/TableTicker.cpp b/tools/profiler/TableTicker.cpp index 2f497c8766b..4cf722771ef 100644 --- a/tools/profiler/TableTicker.cpp +++ b/tools/profiler/TableTicker.cpp @@ -487,9 +487,57 @@ void TableTicker::doNativeBacktrace(ThreadProfile &aProfile, TickSample* aSample 0 }; - ucontext_t *ucontext = reinterpret_cast(aSample->context); - array.count = EHABIStackWalk(ucontext->uc_mcontext, aProfile.GetStackTop(), - sp_array, pc_array, array.size); + const mcontext_t *mcontext = &reinterpret_cast(aSample->context)->uc_mcontext; + mcontext_t savedContext; + PseudoStack *pseudoStack = aProfile.GetPseudoStack(); + + array.count = 0; + // The pseudostack contains an "EnterJIT" frame whenever we enter + // JIT code with profiling enabled; the stack pointer value points + // the saved registers. We use this to unwind resume unwinding + // after encounting JIT code. + for (uint32_t i = pseudoStack->stackSize(); i > 0; --i) { + // The pseudostack grows towards higher indices, so we iterate + // backwards (from callee to caller). + volatile StackEntry &entry = pseudoStack->mStack[i - 1]; + if (!entry.js() && strcmp(entry.label(), "EnterJIT") == 0) { + // Found JIT entry frame. Unwind up to that point (i.e., force + // the stack walk to stop before the block of saved registers; + // note that it yields nondecreasing stack pointers), then restore + // the saved state. + uint32_t *vSP = reinterpret_cast(entry.stackAddress()); + + array.count += EHABIStackWalk(*mcontext, + /* stackBase = */ vSP, + sp_array + array.count, + pc_array + array.count, + array.size - array.count); + + memset(&savedContext, 0, sizeof(savedContext)); + // See also: struct EnterJITStack in js/src/jit/arm/Trampoline-arm.cpp + savedContext.arm_r4 = *vSP++; + savedContext.arm_r5 = *vSP++; + savedContext.arm_r6 = *vSP++; + savedContext.arm_r7 = *vSP++; + savedContext.arm_r8 = *vSP++; + savedContext.arm_r9 = *vSP++; + savedContext.arm_r10 = *vSP++; + savedContext.arm_fp = *vSP++; + savedContext.arm_lr = *vSP++; + savedContext.arm_sp = reinterpret_cast(vSP); + savedContext.arm_pc = savedContext.arm_lr; + mcontext = &savedContext; + } + } + + // Now unwind whatever's left (starting from either the last EnterJIT + // frame or, if no EnterJIT was found, the original registers). + array.count += EHABIStackWalk(*mcontext, + aProfile.GetStackTop(), + sp_array + array.count, + pc_array + array.count, + array.size - array.count); + mergeNativeBacktrace(aProfile, array); } diff --git a/tools/profiler/tests/test_enterjit_osr.js b/tools/profiler/tests/test_enterjit_osr.js new file mode 100644 index 00000000000..9f132c4bfd7 --- /dev/null +++ b/tools/profiler/tests/test_enterjit_osr.js @@ -0,0 +1,58 @@ +// Check that the EnterJIT frame, added by the JIT trampoline and +// usable by a native unwinder to resume unwinding after encountering +// JIT code, is pushed as expected. +function run_test() { + let p = Cc["@mozilla.org/tools/profiler;1"]; + // Just skip the test if the profiler component isn't present. + if (!p) + return; + p = p.getService(Ci.nsIProfiler); + if (!p) + return; + + // This test assumes that it's starting on an empty SPS stack. + // (Note that the other profiler tests also assume the profiler + // isn't already started.) + do_check_true(!p.IsActive()); + + const ms = 5; + p.StartProfiler(100, ms, ["js"], 1); + let profile = (function arbitrary_name(){ + // A frame for |arbitrary_name| has been pushed. + let then = Date.now(); + do { + let n = 10000; + while (--n); // OSR happens here + // Spin until we're sure we have a sample. + } while (Date.now() - then < ms * 2.5); + return p.getProfileData().threads[0].samples; + })(); + do_check_neq(profile.length, 0); + let stack = profile[profile.length - 1].frames.map(f => f.location); + stack = stack.slice(stack.indexOf("js::RunScript") + 1); + + do_print(stack); + // This test needs to not break on platforms and configurations + // where IonMonkey isn't available / enabled. + if (stack.length < 2 || stack[1] != "EnterJIT") { + do_print("No JIT?"); + // Try to check what we can.... + do_check_eq(Math.min(stack.length, 1), 1); + let thisInterp = stack[0]; + do_check_eq(thisInterp.split(" ")[0], "arbitrary_name"); + if (stack.length >= 2) { + let nextFrame = stack[1]; + do_check_neq(nextFrame.split(" ")[0], "arbitrary_name"); + } + } else { + do_check_eq(Math.min(stack.length, 3), 3); + let thisInterp = stack[0]; + let enterJit = stack[1]; + let thisBC = stack[2]; + do_check_eq(thisInterp.split(" ")[0], "arbitrary_name"); + do_check_eq(enterJit, "EnterJIT"); + do_check_eq(thisBC.split(" ")[0], "arbitrary_name"); + } + + p.StopProfiler(); +} diff --git a/tools/profiler/tests/test_enterjit_osr_disabling.js b/tools/profiler/tests/test_enterjit_osr_disabling.js new file mode 100644 index 00000000000..dbf74c93a9b --- /dev/null +++ b/tools/profiler/tests/test_enterjit_osr_disabling.js @@ -0,0 +1,21 @@ +function run_test() { + let p = Cc["@mozilla.org/tools/profiler;1"]; + // Just skip the test if the profiler component isn't present. + if (!p) + return; + p = p.getService(Ci.nsIProfiler); + if (!p) + return; + + do_check_true(!p.IsActive()); + + p.StartProfiler(100, 10, ["js"], 1); + // The function is entered with the profiler enabled + (function (){ + p.StopProfiler(); + let n = 10000; + while (--n); // OSR happens here with the profiler disabled. + // An assertion will fail when this function returns, if the + // SPS stack was misbalanced. + })(); +} diff --git a/tools/profiler/tests/test_enterjit_osr_enabling.js b/tools/profiler/tests/test_enterjit_osr_enabling.js new file mode 100644 index 00000000000..ae696057b7b --- /dev/null +++ b/tools/profiler/tests/test_enterjit_osr_enabling.js @@ -0,0 +1,21 @@ +function run_test() { + let p = Cc["@mozilla.org/tools/profiler;1"]; + // Just skip the test if the profiler component isn't present. + if (!p) + return; + p = p.getService(Ci.nsIProfiler); + if (!p) + return; + + do_check_true(!p.IsActive()); + + // The function is entered with the profiler disabled. + (function (){ + p.StartProfiler(100, 10, ["js"], 1); + let n = 10000; + while (--n); // OSR happens here with the profiler enabled. + // An assertion will fail when this function returns, if the + // SPS stack was misbalanced. + })(); + p.StopProfiler(); +} diff --git a/tools/profiler/tests/xpcshell.ini b/tools/profiler/tests/xpcshell.ini index cc2fd32b1e6..55b330baf03 100644 --- a/tools/profiler/tests/xpcshell.ini +++ b/tools/profiler/tests/xpcshell.ini @@ -9,3 +9,8 @@ skip-if = true [test_run.js] skip-if = true [test_pause.js] +[test_enterjit_osr.js] +[test_enterjit_osr_disabling.js] +skip-if = !debug +[test_enterjit_osr_enabling.js] +skip-if = !debug diff --git a/view/src/moz.build b/view/src/moz.build index b267ad2e9ec..bd4bc847e7b 100644 --- a/view/src/moz.build +++ b/view/src/moz.build @@ -19,3 +19,7 @@ FINAL_LIBRARY = 'gklayout' LOCAL_INCLUDES += [ '/dom/events/', ] + +if CONFIG['GNU_CC'] and CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android': + # Work around bug 986928 + CXXFLAGS += ['-Wno-error=format'] diff --git a/view/src/nsView.cpp b/view/src/nsView.cpp index 5e511453dd3..bb76ddca775 100644 --- a/view/src/nsView.cpp +++ b/view/src/nsView.cpp @@ -8,6 +8,7 @@ #include "mozilla/Attributes.h" #include "mozilla/BasicEvents.h" #include "mozilla/DebugOnly.h" +#include "mozilla/IntegerPrintfMacros.h" #include "mozilla/Likely.h" #include "mozilla/Poison.h" #include "nsIWidget.h" @@ -787,7 +788,7 @@ void nsView::List(FILE* out, int32_t aIndent) const nsrefcnt widgetRefCnt = mWindow->AddRef() - 1; mWindow->Release(); int32_t Z = mWindow->GetZIndex(); - fprintf(out, "(widget=%p[%d] z=%d pos={%d,%d,%d,%d}) ", + fprintf(out, "(widget=%p[%" PRIuPTR "] z=%d pos={%d,%d,%d,%d}) ", (void*)mWindow, widgetRefCnt, Z, nonclientBounds.x, nonclientBounds.y, windowBounds.width, windowBounds.height); diff --git a/webapprt/CommandLineHandler.js b/webapprt/CommandLineHandler.js index f1ac29523be..7ae8736821f 100644 --- a/webapprt/CommandLineHandler.js +++ b/webapprt/CommandLineHandler.js @@ -43,7 +43,10 @@ CommandLineHandler.prototype = { null); // Load the module to start up the app Cu.import("resource://webapprt/modules/Startup.jsm"); - startup(window); + startup(window).then(null, function (aError) { + dump("Error: " + aError + "\n"); + Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit); + }); } }, diff --git a/webapprt/Startup.jsm b/webapprt/Startup.jsm index 40226caeed4..a3e39df0d02 100644 --- a/webapprt/Startup.jsm +++ b/webapprt/Startup.jsm @@ -146,5 +146,5 @@ this.startup = function(window) { } WebappRT.startUpdateService(); - }).then(null, Cu.reportError.bind(Cu)); + }); } diff --git a/webapprt/WebappRT.jsm b/webapprt/WebappRT.jsm index 67320186423..35a965ac2bd 100644 --- a/webapprt/WebappRT.jsm +++ b/webapprt/WebappRT.jsm @@ -30,8 +30,7 @@ XPCOMUtils.defineLazyServiceGetter(this, "appsService", this.WebappRT = { get launchURI() { - let manifest = this.localeManifest; - return manifest.fullLaunchPath(); + return this.localeManifest.fullLaunchPath(); }, get localeManifest() { diff --git a/webapprt/prefs.js b/webapprt/prefs.js index 816833636d7..cdf230ed048 100644 --- a/webapprt/prefs.js +++ b/webapprt/prefs.js @@ -59,6 +59,8 @@ pref("dom.mozAlarms.enabled", true); pref("dom.max_script_run_time", 0); pref("dom.max_chrome_script_run_time", 0); +// The request URL of the GeoLocation backend +pref("geo.wifi.uri", "https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%"); #ifndef RELEASE_BUILD // Enable mozPay default provider diff --git a/widget/cocoa/nsIdleServiceX.mm b/widget/cocoa/nsIdleServiceX.mm index 2e2e84ad62a..234a1541466 100644 --- a/widget/cocoa/nsIdleServiceX.mm +++ b/widget/cocoa/nsIdleServiceX.mm @@ -7,7 +7,7 @@ #include "nsIServiceManager.h" #import -NS_IMPL_ISUPPORTS2(nsIdleServiceX, nsIIdleService, nsIdleService) +NS_IMPL_ISUPPORTS_INHERITED0(nsIdleServiceX, nsIdleService) bool nsIdleServiceX::PollIdleTime(uint32_t *aIdleTime) diff --git a/widget/gonk/GonkMemoryPressureMonitoring.cpp b/widget/gonk/GonkMemoryPressureMonitoring.cpp index 8c4541a4442..618c4c7583d 100644 --- a/widget/gonk/GonkMemoryPressureMonitoring.cpp +++ b/widget/gonk/GonkMemoryPressureMonitoring.cpp @@ -9,6 +9,7 @@ #include "mozilla/FileUtils.h" #include "mozilla/Monitor.h" #include "mozilla/Preferences.h" +#include "mozilla/ProcessPriorityManager.h" #include "mozilla/Services.h" #include "nsIObserver.h" #include "nsIObserverService.h" @@ -169,7 +170,7 @@ public: // We use low-memory-no-forward because each process has its own watcher // and thus there is no need for the main process to forward this event. - rv = NS_DispatchMemoryPressure(MemPressure_New); + rv = DispatchMemoryPressure(MemPressure_New); NS_ENSURE_SUCCESS(rv, rv); // Manually check lowMemFd until we observe that memory pressure is over. @@ -202,7 +203,7 @@ public: NS_ENSURE_SUCCESS(rv, rv); if (memoryPressure) { - rv = NS_DispatchMemoryPressure(MemPressure_Ongoing); + rv = DispatchMemoryPressure(MemPressure_Ongoing); NS_ENSURE_SUCCESS(rv, rv); continue; } @@ -245,6 +246,21 @@ private: return NS_OK; } + /** + * Dispatch the specified memory pressure event unless a high-priority + * process is present. If a high-priority process is present then it's likely + * responding to an urgent event (an incoming call or message for example) so + * avoid wasting CPU time responding to low-memory events. + */ + nsresult DispatchMemoryPressure(MemoryPressureState state) + { + if (ProcessPriorityManager::AnyProcessHasHighPriority()) { + return NS_OK; + } + + return NS_DispatchMemoryPressure(state); + } + Monitor mMonitor; uint32_t mPollMS; bool mShuttingDown; diff --git a/widget/nsINativeMenuService.h b/widget/nsINativeMenuService.h index 239c436331d..405763fe376 100644 --- a/widget/nsINativeMenuService.h +++ b/widget/nsINativeMenuService.h @@ -18,10 +18,13 @@ class nsIContent; class nsINativeMenuService : public nsISupports { public: + NS_DECLARE_STATIC_IID_ACCESSOR(NS_INATIVEMENUSERVICE_IID) // Given a top-level window widget and a menu bar DOM node, sets up native // menus. Once created, native menus are controlled via the DOM, including // destruction. NS_IMETHOD CreateNativeMenuBar(nsIWidget* aParent, nsIContent* aMenuBarNode)=0; }; +NS_DEFINE_STATIC_IID_ACCESSOR(nsINativeMenuService, NS_INATIVEMENUSERVICE_IID) + #endif // nsINativeMenuService_h_ diff --git a/widget/windows/nsLookAndFeel.cpp b/widget/windows/nsLookAndFeel.cpp index 6d40aad7af9..5199947e6e4 100644 --- a/widget/windows/nsLookAndFeel.cpp +++ b/widget/windows/nsLookAndFeel.cpp @@ -369,11 +369,7 @@ nsLookAndFeel::GetIntImpl(IntID aID, int32_t &aResult) // High contrast is a misnomer under Win32 -- any theme can be used with it, // e.g. normal contrast with large fonts, low contrast, etc. // The high contrast flag really means -- use this theme and don't override it. - HIGHCONTRAST contrastThemeInfo; - contrastThemeInfo.cbSize = sizeof(contrastThemeInfo); - ::SystemParametersInfo(SPI_GETHIGHCONTRAST, 0, &contrastThemeInfo, 0); - - aResult = ((contrastThemeInfo.dwFlags & HCF_HIGHCONTRASTON) != 0); + aResult = nsUXThemeData::IsHighContrastOn(); break; case eIntID_ScrollArrowStyle: aResult = eScrollArrowStyle_Single; diff --git a/widget/windows/nsUXThemeData.cpp b/widget/windows/nsUXThemeData.cpp index ef50c30d96c..1ebbf149fb9 100644 --- a/widget/windows/nsUXThemeData.cpp +++ b/widget/windows/nsUXThemeData.cpp @@ -253,6 +253,8 @@ nsUXThemeData::sThemeId = LookAndFeel::eWindowsTheme_Generic; bool nsUXThemeData::sIsDefaultWindowsTheme = false; +bool +nsUXThemeData::sIsHighContrastOn = false; // static LookAndFeel::WindowsTheme @@ -267,6 +269,11 @@ bool nsUXThemeData::IsDefaultWindowTheme() return sIsDefaultWindowsTheme; } +bool nsUXThemeData::IsHighContrastOn() +{ + return sIsHighContrastOn; +} + // static bool nsUXThemeData::CheckForCompositor(bool aUpdateCache) { @@ -292,6 +299,14 @@ nsUXThemeData::UpdateNativeThemeInfo() return; } + HIGHCONTRAST highContrastInfo; + highContrastInfo.cbSize = sizeof(HIGHCONTRAST); + if (SystemParametersInfo(SPI_GETHIGHCONTRAST, 0, &highContrastInfo, 0)) { + sIsHighContrastOn = ((highContrastInfo.dwFlags & HCF_HIGHCONTRASTON) != 0); + } else { + sIsHighContrastOn = false; + } + WCHAR themeFileName[MAX_PATH + 1]; WCHAR themeColor[MAX_PATH + 1]; if (FAILED(GetCurrentThemeName(themeFileName, @@ -317,9 +332,16 @@ nsUXThemeData::UpdateNativeThemeInfo() if (theme == WINTHEME_UNRECOGNIZED) return; - if (theme == WINTHEME_AERO || theme == WINTHEME_AERO_LITE || theme == WINTHEME_LUNA) + // We're using the default theme if we're using any of Aero, Aero Lite, or + // luna. However, on Win8, GetCurrentThemeName (see above) returns + // AeroLite.msstyles for the 4 builtin highcontrast themes as well. Those + // themes "don't count" as default themes, so we specifically check for high + // contrast mode in that situation. + if (!(IsWin8OrLater() && sIsHighContrastOn) && + (theme == WINTHEME_AERO || theme == WINTHEME_AERO_LITE || theme == WINTHEME_LUNA)) { sIsDefaultWindowsTheme = true; - + } + if (theme != WINTHEME_LUNA) { switch(theme) { case WINTHEME_AERO: diff --git a/widget/windows/nsUXThemeData.h b/widget/windows/nsUXThemeData.h index fa93405dbfa..2688ec6592c 100644 --- a/widget/windows/nsUXThemeData.h +++ b/widget/windows/nsUXThemeData.h @@ -92,6 +92,7 @@ public: static SIZE sCommandButtons[4]; static mozilla::LookAndFeel::WindowsTheme sThemeId; static bool sIsDefaultWindowsTheme; + static bool sIsHighContrastOn; static void Initialize(); static void Teardown(); @@ -106,6 +107,7 @@ public: static void UpdateNativeThemeInfo(); static mozilla::LookAndFeel::WindowsTheme GetNativeThemeId(); static bool IsDefaultWindowTheme(); + static bool IsHighContrastOn(); // This method returns the cached compositor state. Most // callers should call without the argument. The cache diff --git a/widget/xpwidgets/APZCCallbackHelper.cpp b/widget/xpwidgets/APZCCallbackHelper.cpp index 3753ee4ba76..fc675dca7ac 100644 --- a/widget/xpwidgets/APZCCallbackHelper.cpp +++ b/widget/xpwidgets/APZCCallbackHelper.cpp @@ -104,9 +104,9 @@ static void RecenterDisplayPort(mozilla::layers::FrameMetrics& aFrameMetrics) { if (!aFrameMetrics.GetUseDisplayPortMargins()) { - CSSRect compositionBounds(aFrameMetrics.CalculateCompositedRectInCssPixels()); - aFrameMetrics.mDisplayPort.x = (compositionBounds.width - aFrameMetrics.mDisplayPort.width) / 2; - aFrameMetrics.mDisplayPort.y = (compositionBounds.height - aFrameMetrics.mDisplayPort.height) / 2; + CSSSize compositionSize = aFrameMetrics.CalculateCompositedSizeInCssPixels(); + aFrameMetrics.mDisplayPort.x = (compositionSize.width - aFrameMetrics.mDisplayPort.width) / 2; + aFrameMetrics.mDisplayPort.y = (compositionSize.height - aFrameMetrics.mDisplayPort.height) / 2; } else { LayerMargin margins = aFrameMetrics.GetDisplayPortMargins(); margins.right = margins.left = margins.LeftRight() / 2; @@ -175,7 +175,7 @@ APZCCallbackHelper::UpdateRootFrame(nsIDOMWindowUtils* aUtils, // be 1000 pixels long but the frame would still be 100 pixels, and so the maximum // scroll range would be 900. Therefore this calculation depends on the zoom applied // to the content relative to the container. - CSSSize scrollPort = CSSSize(aMetrics.CalculateCompositedRectInCssPixels().Size()); + CSSSize scrollPort = aMetrics.CalculateCompositedSizeInCssPixels(); aUtils->SetScrollPositionClampingScrollPortSize(scrollPort.width, scrollPort.height); // Scroll the window to the desired spot diff --git a/xpcom/base/moz.build b/xpcom/base/moz.build index 0a9b5190fcd..6ce9dd576ee 100644 --- a/xpcom/base/moz.build +++ b/xpcom/base/moz.build @@ -157,3 +157,7 @@ LOCAL_INCLUDES += [ if CONFIG['MOZ_OPTIMIZE']: DEFINES['MOZ_OPTIMIZE'] = True + +if CONFIG['GNU_CC'] and CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android': + # Work around bug 986928 + CXXFLAGS += ['-Wno-error=format'] diff --git a/xpcom/base/nsAgg.h b/xpcom/base/nsAgg.h index 487becb52a4..d0988cf8485 100644 --- a/xpcom/base/nsAgg.h +++ b/xpcom/base/nsAgg.h @@ -54,8 +54,8 @@ private: \ Internal() {} \ \ NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); \ - NS_IMETHOD_(nsrefcnt) AddRef(void); \ - NS_IMETHOD_(nsrefcnt) Release(void); \ + NS_IMETHOD_(MozExternalRefCountType) AddRef(void); \ + NS_IMETHOD_(MozExternalRefCountType) Release(void); \ \ NS_DECL_OWNINGTHREAD \ }; \ @@ -107,7 +107,7 @@ static NS_CYCLE_COLLECTION_INNERCLASS NS_CYCLE_COLLECTION_INNERNAME; \ NS_IMPL_AGGREGATED_HELPER(_class) \ \ -NS_IMETHODIMP_(nsrefcnt) \ +NS_IMETHODIMP_(MozExternalRefCountType) \ _class::Internal::AddRef(void) \ { \ _class* agg = (_class*)((char*)(this) - offsetof(_class, fAggregated)); \ @@ -118,7 +118,7 @@ _class::Internal::AddRef(void) \ return agg->mRefCnt; \ } \ \ -NS_IMETHODIMP_(nsrefcnt) \ +NS_IMETHODIMP_(MozExternalRefCountType) \ _class::Internal::Release(void) \ { \ _class* agg = (_class*)((char*)(this) - offsetof(_class, fAggregated)); \ @@ -138,7 +138,7 @@ _class::Internal::Release(void) \ \ NS_IMPL_AGGREGATED_HELPER(_class) \ \ -NS_IMETHODIMP_(nsrefcnt) \ +NS_IMETHODIMP_(MozExternalRefCountType) \ _class::Internal::AddRef(void) \ { \ _class* agg = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Downcast(this); \ @@ -148,7 +148,7 @@ _class::Internal::AddRef(void) \ NS_LOG_ADDREF(this, count, #_class, sizeof(*agg)); \ return count; \ } \ -NS_IMETHODIMP_(nsrefcnt) \ +NS_IMETHODIMP_(MozExternalRefCountType) \ _class::Internal::Release(void) \ { \ _class* agg = NS_CYCLE_COLLECTION_CLASSNAME(_class)::Downcast(this); \ @@ -171,13 +171,13 @@ _class::QueryInterface(const nsIID& aIID, void** aInstancePtr) \ return fOuter->QueryInterface(aIID, aInstancePtr); \ } \ \ -NS_IMETHODIMP_(nsrefcnt) \ +NS_IMETHODIMP_(MozExternalRefCountType) \ _class::AddRef(void) \ { \ return fOuter->AddRef(); \ } \ \ -NS_IMETHODIMP_(nsrefcnt) \ +NS_IMETHODIMP_(MozExternalRefCountType) \ _class::Release(void) \ { \ return fOuter->Release(); \ diff --git a/xpcom/base/nsDebugImpl.cpp b/xpcom/base/nsDebugImpl.cpp index ee54cc17761..018d8162449 100644 --- a/xpcom/base/nsDebugImpl.cpp +++ b/xpcom/base/nsDebugImpl.cpp @@ -77,13 +77,13 @@ static Atomic gAssertionCount; NS_IMPL_QUERY_INTERFACE2(nsDebugImpl, nsIDebug, nsIDebug2) -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) nsDebugImpl::AddRef() { return 2; } -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) nsDebugImpl::Release() { return 1; diff --git a/xpcom/base/nsDumpUtils.cpp b/xpcom/base/nsDumpUtils.cpp index e876f176783..4a1668eaddc 100644 --- a/xpcom/base/nsDumpUtils.cpp +++ b/xpcom/base/nsDumpUtils.cpp @@ -16,6 +16,7 @@ #if defined(XP_LINUX) || defined(__FreeBSD__) // { #include "mozilla/Preferences.h" #include +#include #include #include diff --git a/xpcom/base/nsISupportsBase.h b/xpcom/base/nsISupportsBase.h index d2f66f4a68f..0f8bbbcf33d 100644 --- a/xpcom/base/nsISupportsBase.h +++ b/xpcom/base/nsISupportsBase.h @@ -61,7 +61,7 @@ public: * * @return The resulting reference count. */ - NS_IMETHOD_(nsrefcnt) AddRef(void) = 0; + NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0; /** * Decreases the reference count for this interface. @@ -70,7 +70,7 @@ public: * * @return The resulting reference count. */ - NS_IMETHOD_(nsrefcnt) Release(void) = 0; + NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0; //@} }; diff --git a/xpcom/base/nsMemoryImpl.cpp b/xpcom/base/nsMemoryImpl.cpp index ae6a04f9887..a544e0df806 100644 --- a/xpcom/base/nsMemoryImpl.cpp +++ b/xpcom/base/nsMemoryImpl.cpp @@ -173,8 +173,8 @@ nsMemoryImpl::RunFlushers(const char16_t* aReason) } // XXX need NS_IMPL_STATIC_ADDREF/RELEASE -NS_IMETHODIMP_(nsrefcnt) nsMemoryImpl::FlushEvent::AddRef() { return 2; } -NS_IMETHODIMP_(nsrefcnt) nsMemoryImpl::FlushEvent::Release() { return 1; } +NS_IMETHODIMP_(MozExternalRefCountType) nsMemoryImpl::FlushEvent::AddRef() { return 2; } +NS_IMETHODIMP_(MozExternalRefCountType) nsMemoryImpl::FlushEvent::Release() { return 1; } NS_IMPL_QUERY_INTERFACE1(nsMemoryImpl::FlushEvent, nsIRunnable) NS_IMETHODIMP diff --git a/xpcom/base/nsMemoryImpl.h b/xpcom/base/nsMemoryImpl.h index eba170afa2e..e5cfce178b2 100644 --- a/xpcom/base/nsMemoryImpl.h +++ b/xpcom/base/nsMemoryImpl.h @@ -20,8 +20,8 @@ class nsMemoryImpl : public nsIMemory public: // We don't use the generic macros because we are a special static object NS_IMETHOD QueryInterface(REFNSIID aIID, void** aResult); - NS_IMETHOD_(nsrefcnt) AddRef(void) { return 1; } - NS_IMETHOD_(nsrefcnt) Release(void) { return 1; } + NS_IMETHOD_(MozExternalRefCountType) AddRef(void) { return 1; } + NS_IMETHOD_(MozExternalRefCountType) Release(void) { return 1; } NS_DECL_NSIMEMORY diff --git a/xpcom/base/nsTraceRefcnt.cpp b/xpcom/base/nsTraceRefcnt.cpp index e3b18257de4..d3944bf31a0 100644 --- a/xpcom/base/nsTraceRefcnt.cpp +++ b/xpcom/base/nsTraceRefcnt.cpp @@ -1011,7 +1011,7 @@ NS_LogAddRef(void* aPtr, nsrefcnt aRefcnt, else { // Can't use PR_LOG(), b/c it truncates the line fprintf(gRefcntsLog, - "\n<%s> 0x%08X %" PRIdPTR " AddRef %d\n", aClazz, NS_PTR_TO_INT32(aPtr), serialno, aRefcnt); + "\n<%s> 0x%08X %" PRIuPTR " AddRef %" PRIuPTR "\n", aClazz, NS_PTR_TO_INT32(aPtr), serialno, aRefcnt); nsTraceRefcnt::WalkTheStack(gRefcntsLog); fflush(gRefcntsLog); } @@ -1059,7 +1059,7 @@ NS_LogRelease(void* aPtr, nsrefcnt aRefcnt, const char* aClazz) else { // Can't use PR_LOG(), b/c it truncates the line fprintf(gRefcntsLog, - "\n<%s> 0x%08X %" PRIdPTR " Release %d\n", aClazz, NS_PTR_TO_INT32(aPtr), serialno, aRefcnt); + "\n<%s> 0x%08X %" PRIuPTR " Release %" PRIuPTR "\n", aClazz, NS_PTR_TO_INT32(aPtr), serialno, aRefcnt); nsTraceRefcnt::WalkTheStack(gRefcntsLog); fflush(gRefcntsLog); } diff --git a/xpcom/components/nsCategoryManager.cpp b/xpcom/components/nsCategoryManager.cpp index 50331b6b8c2..622168e79aa 100644 --- a/xpcom/components/nsCategoryManager.cpp +++ b/xpcom/components/nsCategoryManager.cpp @@ -402,13 +402,13 @@ CategoryEnumerator::enumfunc_createenumerator(const char* aStr, CategoryNode* aN NS_IMPL_QUERY_INTERFACE2(nsCategoryManager, nsICategoryManager, nsIMemoryReporter) -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) nsCategoryManager::AddRef() { return 2; } -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) nsCategoryManager::Release() { return 1; diff --git a/xpcom/ds/nsAtomTable.cpp b/xpcom/ds/nsAtomTable.cpp index acc7c7b744f..a448ece41fb 100644 --- a/xpcom/ds/nsAtomTable.cpp +++ b/xpcom/ds/nsAtomTable.cpp @@ -123,8 +123,8 @@ public: {} ~PermanentAtomImpl(); - NS_IMETHOD_(nsrefcnt) AddRef(); - NS_IMETHOD_(nsrefcnt) Release(); + NS_IMETHOD_(MozExternalRefCountType) AddRef(); + NS_IMETHOD_(MozExternalRefCountType) Release(); virtual bool IsPermanent(); @@ -393,13 +393,13 @@ PermanentAtomImpl::~PermanentAtomImpl() mRefCnt = REFCNT_PERMANENT_SENTINEL; } -NS_IMETHODIMP_(nsrefcnt) PermanentAtomImpl::AddRef() +NS_IMETHODIMP_(MozExternalRefCountType) PermanentAtomImpl::AddRef() { MOZ_ASSERT(NS_IsMainThread(), "wrong thread"); return 2; } -NS_IMETHODIMP_(nsrefcnt) PermanentAtomImpl::Release() +NS_IMETHODIMP_(MozExternalRefCountType) PermanentAtomImpl::Release() { MOZ_ASSERT(NS_IsMainThread(), "wrong thread"); return 1; diff --git a/xpcom/ds/nsExpirationTracker.h b/xpcom/ds/nsExpirationTracker.h index cec0ec32d04..e71af321619 100644 --- a/xpcom/ds/nsExpirationTracker.h +++ b/xpcom/ds/nsExpirationTracker.h @@ -341,7 +341,7 @@ nsExpirationTracker::ExpirationTrackerObserver::Observe(nsISupports *a } template -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) nsExpirationTracker::ExpirationTrackerObserver::AddRef(void) { MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); @@ -352,7 +352,7 @@ nsExpirationTracker::ExpirationTrackerObserver::AddRef(void) } template -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) nsExpirationTracker::ExpirationTrackerObserver::Release(void) { MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); diff --git a/xpcom/glue/nsClassInfoImpl.cpp b/xpcom/glue/nsClassInfoImpl.cpp index e979e62c22a..6e685f125e4 100644 --- a/xpcom/glue/nsClassInfoImpl.cpp +++ b/xpcom/glue/nsClassInfoImpl.cpp @@ -5,13 +5,13 @@ #include "nsIClassInfoImpl.h" #include "nsIProgrammingLanguage.h" -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) GenericClassInfo::AddRef() { return 2; } -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) GenericClassInfo::Release() { return 1; diff --git a/xpcom/glue/nsCycleCollectionParticipant.h b/xpcom/glue/nsCycleCollectionParticipant.h index a859e04755e..365b3ba6fd7 100644 --- a/xpcom/glue/nsCycleCollectionParticipant.h +++ b/xpcom/glue/nsCycleCollectionParticipant.h @@ -9,7 +9,7 @@ #include "nsCycleCollectionNoteChild.h" #include "js/RootingAPI.h" -#define NS_CYCLECOLLECTIONPARTICIPANT_IID \ +#define NS_XPCOMCYCLECOLLECTIONPARTICIPANT_IID \ { \ 0x9674489b, \ 0x1f6f, \ @@ -95,8 +95,6 @@ public: MOZ_CONSTEXPR nsCycleCollectionParticipant() : mMightSkip(false) {} MOZ_CONSTEXPR nsCycleCollectionParticipant(bool aSkip) : mMightSkip(aSkip) {} - NS_DECLARE_STATIC_IID_ACCESSOR(NS_CYCLECOLLECTIONPARTICIPANT_IID) - NS_IMETHOD Traverse(void *p, nsCycleCollectionTraversalCallback &cb) = 0; NS_IMETHOD_(void) Root(void *p) = 0; @@ -153,9 +151,6 @@ private: const bool mMightSkip; }; -NS_DEFINE_STATIC_IID_ACCESSOR(nsCycleCollectionParticipant, - NS_CYCLECOLLECTIONPARTICIPANT_IID) - class NS_NO_VTABLE nsScriptObjectTracer : public nsCycleCollectionParticipant { public: @@ -174,6 +169,8 @@ public: MOZ_CONSTEXPR nsXPCOMCycleCollectionParticipant() : nsScriptObjectTracer(false) {} MOZ_CONSTEXPR nsXPCOMCycleCollectionParticipant(bool aSkip) : nsScriptObjectTracer(aSkip) {} + NS_DECLARE_STATIC_IID_ACCESSOR(NS_XPCOMCYCLECOLLECTIONPARTICIPANT_IID) + NS_IMETHOD_(void) Root(void *p); NS_IMETHOD_(void) Unroot(void *p); @@ -182,6 +179,9 @@ public: static bool CheckForRightISupports(nsISupports *s); }; +NS_DEFINE_STATIC_IID_ACCESSOR(nsXPCOMCycleCollectionParticipant, + NS_XPCOMCYCLECOLLECTIONPARTICIPANT_IID) + /////////////////////////////////////////////////////////////////////////////// // Helpers for implementing a QI to nsXPCOMCycleCollectionParticipant /////////////////////////////////////////////////////////////////////////////// diff --git a/xpcom/glue/nsEnumeratorUtils.cpp b/xpcom/glue/nsEnumeratorUtils.cpp index 1888e9b576a..3d190287a29 100644 --- a/xpcom/glue/nsEnumeratorUtils.cpp +++ b/xpcom/glue/nsEnumeratorUtils.cpp @@ -35,12 +35,12 @@ public: }; // nsISupports interface -NS_IMETHODIMP_(nsrefcnt) EmptyEnumeratorImpl::AddRef(void) +NS_IMETHODIMP_(MozExternalRefCountType) EmptyEnumeratorImpl::AddRef(void) { return 2; } -NS_IMETHODIMP_(nsrefcnt) EmptyEnumeratorImpl::Release(void) +NS_IMETHODIMP_(MozExternalRefCountType) EmptyEnumeratorImpl::Release(void) { return 1; } diff --git a/xpcom/glue/nsISupportsImpl.h b/xpcom/glue/nsISupportsImpl.h index cedb1d7e100..99ed401923b 100644 --- a/xpcom/glue/nsISupportsImpl.h +++ b/xpcom/glue/nsISupportsImpl.h @@ -283,8 +283,8 @@ class ThreadSafeAutoRefCnt { public: \ NS_IMETHOD QueryInterface(REFNSIID aIID, \ void** aInstancePtr); \ - NS_IMETHOD_(nsrefcnt) AddRef(void); \ - NS_IMETHOD_(nsrefcnt) Release(void); \ + NS_IMETHOD_(MozExternalRefCountType) AddRef(void); \ + NS_IMETHOD_(MozExternalRefCountType) Release(void); \ protected: \ nsAutoRefCnt mRefCnt; \ NS_DECL_OWNINGTHREAD \ @@ -294,8 +294,8 @@ public: public: \ NS_IMETHOD QueryInterface(REFNSIID aIID, \ void** aInstancePtr); \ - NS_IMETHOD_(nsrefcnt) AddRef(void); \ - NS_IMETHOD_(nsrefcnt) Release(void); \ + NS_IMETHOD_(MozExternalRefCountType) AddRef(void); \ + NS_IMETHOD_(MozExternalRefCountType) Release(void); \ protected: \ ::mozilla::ThreadSafeAutoRefCnt mRefCnt; \ NS_DECL_OWNINGTHREAD \ @@ -305,8 +305,8 @@ public: public: \ NS_IMETHOD QueryInterface(REFNSIID aIID, \ void** aInstancePtr); \ - NS_IMETHOD_(nsrefcnt) AddRef(void); \ - NS_IMETHOD_(nsrefcnt) Release(void); \ + NS_IMETHOD_(MozExternalRefCountType) AddRef(void); \ + NS_IMETHOD_(MozExternalRefCountType) Release(void); \ NS_IMETHOD_(void) DeleteCycleCollectable(void); \ protected: \ nsCycleCollectingAutoRefCnt mRefCnt; \ @@ -340,13 +340,13 @@ public: return count; #define NS_IMPL_CYCLE_COLLECTING_NATIVE_ADDREF(_class) \ -NS_METHOD_(nsrefcnt) _class::AddRef(void) \ +NS_METHOD_(MozExternalRefCountType) _class::AddRef(void) \ { \ NS_IMPL_CC_NATIVE_ADDREF_BODY(_class) \ } #define NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE_WITH_LAST_RELEASE(_class, _last) \ -NS_METHOD_(nsrefcnt) _class::Release(void) \ +NS_METHOD_(MozExternalRefCountType) _class::Release(void) \ { \ MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \ NS_ASSERT_OWNINGTHREAD(_class); \ @@ -371,17 +371,17 @@ NS_METHOD_(nsrefcnt) _class::Release(void) } #define NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE(_class) \ -NS_METHOD_(nsrefcnt) _class::Release(void) \ +NS_METHOD_(MozExternalRefCountType) _class::Release(void) \ { \ NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \ } #define NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(_class) \ public: \ - NS_METHOD_(nsrefcnt) AddRef(void) { \ + NS_METHOD_(MozExternalRefCountType) AddRef(void) { \ NS_IMPL_CC_NATIVE_ADDREF_BODY(_class) \ } \ - NS_METHOD_(nsrefcnt) Release(void) { \ + NS_METHOD_(MozExternalRefCountType) Release(void) { \ NS_IMPL_CC_NATIVE_RELEASE_BODY(_class) \ } \ protected: \ @@ -407,14 +407,14 @@ public: */ #define NS_INLINE_DECL_REFCOUNTING(_class) \ public: \ - NS_METHOD_(nsrefcnt) AddRef(void) { \ + NS_METHOD_(MozExternalRefCountType) AddRef(void) { \ MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \ NS_ASSERT_OWNINGTHREAD(_class); \ ++mRefCnt; \ NS_LOG_ADDREF(this, mRefCnt, #_class, sizeof(*this)); \ return mRefCnt; \ } \ - NS_METHOD_(nsrefcnt) Release(void) { \ + NS_METHOD_(MozExternalRefCountType) Release(void) { \ MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \ NS_ASSERT_OWNINGTHREAD(_class); \ --mRefCnt; \ @@ -442,13 +442,13 @@ public: */ #define NS_INLINE_DECL_THREADSAFE_REFCOUNTING(_class) \ public: \ - NS_METHOD_(nsrefcnt) AddRef(void) { \ + NS_METHOD_(MozExternalRefCountType) AddRef(void) { \ MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \ nsrefcnt count = ++mRefCnt; \ NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \ return (nsrefcnt) count; \ } \ - NS_METHOD_(nsrefcnt) Release(void) { \ + NS_METHOD_(MozExternalRefCountType) Release(void) { \ MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \ nsrefcnt count = --mRefCnt; \ NS_LOG_RELEASE(this, count, #_class); \ @@ -467,7 +467,7 @@ public: * @param _class The name of the class implementing the method */ #define NS_IMPL_ADDREF(_class) \ -NS_IMETHODIMP_(nsrefcnt) _class::AddRef(void) \ +NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) \ { \ MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \ if (!mRefCnt.isThreadSafe) \ @@ -485,7 +485,7 @@ NS_IMETHODIMP_(nsrefcnt) _class::AddRef(void) \ * @param _aggregator the owning/containing object */ #define NS_IMPL_ADDREF_USING_AGGREGATOR(_class, _aggregator) \ -NS_IMETHODIMP_(nsrefcnt) _class::AddRef(void) \ +NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) \ { \ NS_PRECONDITION(_aggregator, "null aggregator"); \ return (_aggregator)->AddRef(); \ @@ -511,7 +511,7 @@ NS_IMETHODIMP_(nsrefcnt) _class::AddRef(void) \ * of object allocated with placement new). */ #define NS_IMPL_RELEASE_WITH_DESTROY(_class, _destroy) \ -NS_IMETHODIMP_(nsrefcnt) _class::Release(void) \ +NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) \ { \ MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \ if (!mRefCnt.isThreadSafe) \ @@ -552,7 +552,7 @@ NS_IMETHODIMP_(nsrefcnt) _class::Release(void) \ * @param _aggregator the owning/containing object */ #define NS_IMPL_RELEASE_USING_AGGREGATOR(_class, _aggregator) \ -NS_IMETHODIMP_(nsrefcnt) _class::Release(void) \ +NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) \ { \ NS_PRECONDITION(_aggregator, "null aggregator"); \ return (_aggregator)->Release(); \ @@ -560,7 +560,7 @@ NS_IMETHODIMP_(nsrefcnt) _class::Release(void) \ #define NS_IMPL_CYCLE_COLLECTING_ADDREF(_class) \ -NS_IMETHODIMP_(nsrefcnt) _class::AddRef(void) \ +NS_IMETHODIMP_(MozExternalRefCountType) _class::AddRef(void) \ { \ MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \ NS_ASSERT_OWNINGTHREAD(_class); \ @@ -571,7 +571,7 @@ NS_IMETHODIMP_(nsrefcnt) _class::AddRef(void) \ } #define NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(_class, _destroy) \ -NS_IMETHODIMP_(nsrefcnt) _class::Release(void) \ +NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) \ { \ MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \ NS_ASSERT_OWNINGTHREAD(_class); \ @@ -591,7 +591,7 @@ NS_IMETHODIMP_(void) _class::DeleteCycleCollectable(void) \ // _LAST_RELEASE can be useful when certain resources should be released // as soon as we know the object will be deleted. #define NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(_class, _last) \ -NS_IMETHODIMP_(nsrefcnt) _class::Release(void) \ +NS_IMETHODIMP_(MozExternalRefCountType) _class::Release(void) \ { \ MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \ NS_ASSERT_OWNINGTHREAD(_class); \ @@ -963,6 +963,25 @@ NS_IMETHODIMP _class::QueryInterface(REFNSIID aIID, void** aInstancePtr) \ NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(_class, nsISupports, _i1) \ NS_INTERFACE_TABLE_END +#define NS_INTERFACE_TABLE13(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, \ + _i8, _i9, _i10, _i11, _i12, _i13) \ + NS_INTERFACE_TABLE_BEGIN \ + NS_INTERFACE_TABLE_ENTRY(_class, _i1) \ + NS_INTERFACE_TABLE_ENTRY(_class, _i2) \ + NS_INTERFACE_TABLE_ENTRY(_class, _i3) \ + NS_INTERFACE_TABLE_ENTRY(_class, _i4) \ + NS_INTERFACE_TABLE_ENTRY(_class, _i5) \ + NS_INTERFACE_TABLE_ENTRY(_class, _i6) \ + NS_INTERFACE_TABLE_ENTRY(_class, _i7) \ + NS_INTERFACE_TABLE_ENTRY(_class, _i8) \ + NS_INTERFACE_TABLE_ENTRY(_class, _i9) \ + NS_INTERFACE_TABLE_ENTRY(_class, _i10) \ + NS_INTERFACE_TABLE_ENTRY(_class, _i11) \ + NS_INTERFACE_TABLE_ENTRY(_class, _i12) \ + NS_INTERFACE_TABLE_ENTRY(_class, _i13) \ + NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(_class, nsISupports, _i1) \ + NS_INTERFACE_TABLE_END + #define NS_IMPL_QUERY_INTERFACE0(_class) \ NS_INTERFACE_TABLE_HEAD(_class) \ NS_INTERFACE_TABLE0(_class) \ @@ -1036,6 +1055,12 @@ NS_IMETHODIMP _class::QueryInterface(REFNSIID aIID, void** aInstancePtr) \ _i9, _i10, _i11, _i12) \ NS_INTERFACE_TABLE_TAIL +#define NS_IMPL_QUERY_INTERFACE13(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9, _i10, _i11, _i12, _i13) \ + NS_INTERFACE_TABLE_HEAD(_class) \ + NS_INTERFACE_TABLE13(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, \ + _i9, _i10, _i11, _i12, _i13) \ + NS_INTERFACE_TABLE_TAIL /** * Declare that you're going to inherit from something that already @@ -1053,8 +1078,8 @@ NS_IMETHODIMP _class::QueryInterface(REFNSIID aIID, void** aInstancePtr) \ public: \ NS_IMETHOD QueryInterface(REFNSIID aIID, \ void** aInstancePtr); \ - NS_IMETHOD_(nsrefcnt) AddRef(void); \ - NS_IMETHOD_(nsrefcnt) Release(void); \ + NS_IMETHOD_(MozExternalRefCountType) AddRef(void); \ + NS_IMETHOD_(MozExternalRefCountType) Release(void); \ /** * These macros can be used in conjunction with NS_DECL_ISUPPORTS_INHERITED @@ -1065,7 +1090,7 @@ public: \ */ #define NS_IMPL_ADDREF_INHERITED(Class, Super) \ -NS_IMETHODIMP_(nsrefcnt) Class::AddRef(void) \ +NS_IMETHODIMP_(MozExternalRefCountType) Class::AddRef(void) \ { \ nsrefcnt r = Super::AddRef(); \ NS_LOG_ADDREF(this, r, #Class, sizeof(*this)); \ @@ -1073,7 +1098,7 @@ NS_IMETHODIMP_(nsrefcnt) Class::AddRef(void) \ } #define NS_IMPL_RELEASE_INHERITED(Class, Super) \ -NS_IMETHODIMP_(nsrefcnt) Class::Release(void) \ +NS_IMETHODIMP_(MozExternalRefCountType) Class::Release(void) \ { \ nsrefcnt r = Super::Release(); \ NS_LOG_RELEASE(this, r, #Class); \ @@ -1085,13 +1110,13 @@ NS_IMETHODIMP_(nsrefcnt) Class::Release(void) \ * class might be aggregated. */ #define NS_IMPL_NONLOGGING_ADDREF_INHERITED(Class, Super) \ -NS_IMETHODIMP_(nsrefcnt) Class::AddRef(void) \ +NS_IMETHODIMP_(MozExternalRefCountType) Class::AddRef(void) \ { \ return Super::AddRef(); \ } #define NS_IMPL_NONLOGGING_RELEASE_INHERITED(Class, Super) \ -NS_IMETHODIMP_(nsrefcnt) Class::Release(void) \ +NS_IMETHODIMP_(MozExternalRefCountType) Class::Release(void) \ { \ return Super::Release(); \ } @@ -1366,6 +1391,13 @@ NS_IMETHODIMP_(nsrefcnt) Class::Release(void) \ NS_IMPL_QUERY_INTERFACE12(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, \ _i9, _i10, _i11, _i12) +#define NS_IMPL_ISUPPORTS13(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, \ + _i9, _i10, _i11, _i12, _i13) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE13(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, \ + _i9, _i10, _i11, _i12, _i13) + #define NS_IMPL_ISUPPORTS_INHERITED0(Class, Super) \ NS_IMPL_QUERY_INTERFACE_INHERITED0(Class, Super) \ NS_IMPL_ADDREF_INHERITED(Class, Super) \ diff --git a/xpcom/io/nsPipe3.cpp b/xpcom/io/nsPipe3.cpp index d2e63a447a1..b11dcf1647b 100644 --- a/xpcom/io/nsPipe3.cpp +++ b/xpcom/io/nsPipe3.cpp @@ -682,14 +682,14 @@ nsPipeInputStream::OnInputException(nsresult reason, nsPipeEvents &events) return result; } -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) nsPipeInputStream::AddRef(void) { ++mReaderRefCnt; return mPipe->AddRef(); } -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) nsPipeInputStream::Release(void) { if (--mReaderRefCnt == 0) @@ -1037,14 +1037,14 @@ nsPipeOutputStream::OnOutputException(nsresult reason, nsPipeEvents &events) } -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) nsPipeOutputStream::AddRef() { ++mWriterRefCnt; return mPipe->AddRef(); } -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) nsPipeOutputStream::Release() { if (--mWriterRefCnt == 0) diff --git a/xpcom/io/nsUnicharInputStream.cpp b/xpcom/io/nsUnicharInputStream.cpp index 49346133e2c..b639d8d1146 100644 --- a/xpcom/io/nsUnicharInputStream.cpp +++ b/xpcom/io/nsUnicharInputStream.cpp @@ -373,8 +373,8 @@ NS_IMPL_QUERY_INTERFACE2(nsSimpleUnicharStreamFactory, nsIFactory, nsISimpleUnicharStreamFactory) -NS_IMETHODIMP_(nsrefcnt) nsSimpleUnicharStreamFactory::AddRef() { return 2; } -NS_IMETHODIMP_(nsrefcnt) nsSimpleUnicharStreamFactory::Release() { return 1; } +NS_IMETHODIMP_(MozExternalRefCountType) nsSimpleUnicharStreamFactory::AddRef() { return 2; } +NS_IMETHODIMP_(MozExternalRefCountType) nsSimpleUnicharStreamFactory::Release() { return 1; } NS_IMETHODIMP nsSimpleUnicharStreamFactory::CreateInstance(nsISupports* aOuter, REFNSIID aIID, diff --git a/xpcom/reflect/xptcall/src/xptcall.cpp b/xpcom/reflect/xptcall/src/xptcall.cpp index a33b1e70051..b87deba3c9d 100644 --- a/xpcom/reflect/xptcall/src/xptcall.cpp +++ b/xpcom/reflect/xptcall/src/xptcall.cpp @@ -24,13 +24,13 @@ nsXPTCStubBase::QueryInterface(REFNSIID aIID, return mOuter->QueryInterface(aIID, aInstancePtr); } -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) nsXPTCStubBase::AddRef() { return mOuter->AddRef(); } -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) nsXPTCStubBase::Release() { return mOuter->Release(); diff --git a/xpcom/reflect/xptinfo/src/moz.build b/xpcom/reflect/xptinfo/src/moz.build index cc4a3279638..48a109e0848 100644 --- a/xpcom/reflect/xptinfo/src/moz.build +++ b/xpcom/reflect/xptinfo/src/moz.build @@ -13,9 +13,4 @@ UNIFIED_SOURCES += [ MSVC_ENABLE_PGO = True -# For nsManifestLineReader class. -LOCAL_INCLUDES += [ - '/xpcom/ds', -] - FINAL_LIBRARY = 'xpcom_core' diff --git a/xpcom/reflect/xptinfo/src/xptiInterfaceInfo.cpp b/xpcom/reflect/xptinfo/src/xptiInterfaceInfo.cpp index a5414ec2c0d..96db6e258d3 100644 --- a/xpcom/reflect/xptinfo/src/xptiInterfaceInfo.cpp +++ b/xpcom/reflect/xptinfo/src/xptiInterfaceInfo.cpp @@ -591,7 +591,7 @@ xptiInterfaceInfo::~xptiInterfaceInfo() NS_ASSERTION(!mEntry, "bad state in dtor"); } -nsrefcnt +MozExternalRefCountType xptiInterfaceInfo::AddRef(void) { nsrefcnt cnt = ++mRefCnt; @@ -599,7 +599,7 @@ xptiInterfaceInfo::AddRef(void) return cnt; } -nsrefcnt +MozExternalRefCountType xptiInterfaceInfo::Release(void) { xptiInterfaceEntry* entry = mEntry; diff --git a/xpcom/tests/TestCOMArray.cpp b/xpcom/tests/TestCOMArray.cpp index 7672f01a203..12a13d88e56 100644 --- a/xpcom/tests/TestCOMArray.cpp +++ b/xpcom/tests/TestCOMArray.cpp @@ -18,7 +18,7 @@ public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_IFOO_IID) - NS_IMETHOD_(nsrefcnt) RefCnt() = 0; + NS_IMETHOD_(MozExternalRefCountType) RefCnt() = 0; NS_IMETHOD_(int32_t) ID() = 0; }; @@ -34,7 +34,7 @@ public: NS_DECL_ISUPPORTS // IFoo implementation - NS_IMETHOD_(nsrefcnt) RefCnt() { return mRefCnt; } + NS_IMETHOD_(MozExternalRefCountType) RefCnt() { return mRefCnt; } NS_IMETHOD_(int32_t) ID() { return mID; } static int32_t gCount; @@ -108,7 +108,7 @@ Bar::~Bar() NS_IMPL_ADDREF(Bar) NS_IMPL_QUERY_INTERFACE1(Bar, IBar) -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) Bar::Release(void) { ++Bar::sReleaseCalled; diff --git a/xpcom/tests/TestCOMPtr.cpp b/xpcom/tests/TestCOMPtr.cpp index 30b5079245c..0fed0e43f9a 100644 --- a/xpcom/tests/TestCOMPtr.cpp +++ b/xpcom/tests/TestCOMPtr.cpp @@ -22,8 +22,8 @@ class IFoo : public nsISupports // virtual dtor because IBar uses our Release() virtual ~IFoo(); - NS_IMETHOD_(nsrefcnt) AddRef(); - NS_IMETHOD_(nsrefcnt) Release(); + NS_IMETHOD_(MozExternalRefCountType) AddRef(); + NS_IMETHOD_(MozExternalRefCountType) Release(); NS_IMETHOD QueryInterface( const nsIID&, void** ); static void print_totals(); @@ -101,7 +101,7 @@ IFoo::~IFoo() static_cast(this), total_destructions_); } -nsrefcnt +MozExternalRefCountType IFoo::AddRef() { ++refcount_; @@ -110,7 +110,7 @@ IFoo::AddRef() return refcount_; } -nsrefcnt +MozExternalRefCountType IFoo::Release() { int newcount = --refcount_; diff --git a/xpcom/tests/TestHarness.h b/xpcom/tests/TestHarness.h index 9a24dbc9ff2..2d07a990755 100644 --- a/xpcom/tests/TestHarness.h +++ b/xpcom/tests/TestHarness.h @@ -269,13 +269,13 @@ NS_IMPL_QUERY_INTERFACE2( nsIDirectoryServiceProvider2 ) -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) ScopedXPCOM::AddRef() { return 2; } -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) ScopedXPCOM::Release() { return 1; diff --git a/xpcom/tests/TestHashtables.cpp b/xpcom/tests/TestHashtables.cpp index c14891d99c9..5d3ac01b912 100644 --- a/xpcom/tests/TestHashtables.cpp +++ b/xpcom/tests/TestHashtables.cpp @@ -199,8 +199,8 @@ class IFoo MOZ_FINAL : public nsISupports IFoo(); - NS_IMETHOD_(nsrefcnt) AddRef(); - NS_IMETHOD_(nsrefcnt) Release(); + NS_IMETHOD_(MozExternalRefCountType) AddRef(); + NS_IMETHOD_(MozExternalRefCountType) Release(); NS_IMETHOD QueryInterface( const nsIID&, void** ); NS_IMETHOD SetString(const nsACString& /*in*/ aString); @@ -245,7 +245,7 @@ IFoo::~IFoo() static_cast(this), total_destructions_); } -nsrefcnt +MozExternalRefCountType IFoo::AddRef() { ++refcount_; @@ -254,7 +254,7 @@ IFoo::AddRef() return refcount_; } -nsrefcnt +MozExternalRefCountType IFoo::Release() { int newcount = --refcount_; diff --git a/xpcom/tests/TestRacingServiceManager.cpp b/xpcom/tests/TestRacingServiceManager.cpp index d78eb713be5..0f3214fdf50 100644 --- a/xpcom/tests/TestRacingServiceManager.cpp +++ b/xpcom/tests/TestRacingServiceManager.cpp @@ -121,7 +121,6 @@ NS_IMPL_ADDREF(Component1) NS_IMPL_RELEASE(Component1) NS_INTERFACE_MAP_BEGIN(Component1) - NS_INTERFACE_MAP_ENTRY(Component1) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END @@ -141,7 +140,6 @@ NS_IMPL_ADDREF(Component2) NS_IMPL_RELEASE(Component2) NS_INTERFACE_MAP_BEGIN(Component2) - NS_INTERFACE_MAP_ENTRY(Component2) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END diff --git a/xpcom/tests/TestRefPtr.cpp b/xpcom/tests/TestRefPtr.cpp index c4a74e79e19..55a503a82c7 100644 --- a/xpcom/tests/TestRefPtr.cpp +++ b/xpcom/tests/TestRefPtr.cpp @@ -23,8 +23,8 @@ class Foo : public nsISupports // virtual dtor because Bar uses our Release() virtual ~Foo(); - NS_IMETHOD_(nsrefcnt) AddRef(); - NS_IMETHOD_(nsrefcnt) Release(); + NS_IMETHOD_(MozExternalRefCountType) AddRef(); + NS_IMETHOD_(MozExternalRefCountType) Release(); NS_IMETHOD QueryInterface( const nsIID&, void** ); static void print_totals(); @@ -102,7 +102,7 @@ Foo::~Foo() static_cast(this), total_destructions_); } -nsrefcnt +MozExternalRefCountType Foo::AddRef() { ++refcount_; @@ -111,7 +111,7 @@ Foo::AddRef() return refcount_; } -nsrefcnt +MozExternalRefCountType Foo::Release() { int newcount = --refcount_; diff --git a/xpcom/tests/windows/TestCOM.cpp b/xpcom/tests/windows/TestCOM.cpp index a932fa8c6b4..51947a20dec 100644 --- a/xpcom/tests/windows/TestCOM.cpp +++ b/xpcom/tests/windows/TestCOM.cpp @@ -50,7 +50,7 @@ private: NS_IMPL_QUERY_INTERFACE1(nsTestCom, nsITestCom) -nsrefcnt nsTestCom::AddRef() +MozExternalRefCountType nsTestCom::AddRef() { nsrefcnt res = ++mRefCnt; NS_LOG_ADDREF(this, mRefCnt, "nsTestCom", sizeof(*this)); @@ -58,7 +58,7 @@ nsrefcnt nsTestCom::AddRef() return res; } -nsrefcnt nsTestCom::Release() +MozExternalRefCountType nsTestCom::Release() { nsrefcnt res = --mRefCnt; NS_LOG_RELEASE(this, mRefCnt, "nsTestCom"); diff --git a/xpcom/threads/LazyIdleThread.cpp b/xpcom/threads/LazyIdleThread.cpp index 4bc8da9dfaa..ee27e632f06 100644 --- a/xpcom/threads/LazyIdleThread.cpp +++ b/xpcom/threads/LazyIdleThread.cpp @@ -344,7 +344,7 @@ LazyIdleThread::SelfDestruct() NS_IMPL_ADDREF(LazyIdleThread) -NS_IMETHODIMP_(nsrefcnt) +NS_IMETHODIMP_(MozExternalRefCountType) LazyIdleThread::Release() { nsrefcnt count = --mRefCnt; diff --git a/xpcom/threads/nsThread.cpp b/xpcom/threads/nsThread.cpp index dd88fa4e6ce..017ecbdfa86 100644 --- a/xpcom/threads/nsThread.cpp +++ b/xpcom/threads/nsThread.cpp @@ -91,8 +91,8 @@ public: nsThreadClassInfo() {} }; -NS_IMETHODIMP_(nsrefcnt) nsThreadClassInfo::AddRef() { return 2; } -NS_IMETHODIMP_(nsrefcnt) nsThreadClassInfo::Release() { return 1; } +NS_IMETHODIMP_(MozExternalRefCountType) nsThreadClassInfo::AddRef() { return 2; } +NS_IMETHODIMP_(MozExternalRefCountType) nsThreadClassInfo::Release() { return 1; } NS_IMPL_QUERY_INTERFACE1(nsThreadClassInfo, nsIClassInfo) NS_IMETHODIMP diff --git a/xpcom/threads/nsThreadManager.cpp b/xpcom/threads/nsThreadManager.cpp index 44a8f5e474c..21a37abc463 100644 --- a/xpcom/threads/nsThreadManager.cpp +++ b/xpcom/threads/nsThreadManager.cpp @@ -43,8 +43,8 @@ AppendAndRemoveThread(PRThread *key, nsRefPtr &thread, void *arg) } // statically allocated instance -NS_IMETHODIMP_(nsrefcnt) nsThreadManager::AddRef() { return 2; } -NS_IMETHODIMP_(nsrefcnt) nsThreadManager::Release() { return 1; } +NS_IMETHODIMP_(MozExternalRefCountType) nsThreadManager::AddRef() { return 2; } +NS_IMETHODIMP_(MozExternalRefCountType) nsThreadManager::Release() { return 1; } NS_IMPL_CLASSINFO(nsThreadManager, nullptr, nsIClassInfo::THREADSAFE | nsIClassInfo::SINGLETON, NS_THREADMANAGER_CID) diff --git a/xpcom/threads/nsTimerImpl.cpp b/xpcom/threads/nsTimerImpl.cpp index 3aa9e606e24..eeff7cd81ac 100644 --- a/xpcom/threads/nsTimerImpl.cpp +++ b/xpcom/threads/nsTimerImpl.cpp @@ -194,7 +194,7 @@ void TimerEventAllocator::Free(void* aPtr) NS_IMPL_QUERY_INTERFACE1(nsTimerImpl, nsITimer) NS_IMPL_ADDREF(nsTimerImpl) -NS_IMETHODIMP_(nsrefcnt) nsTimerImpl::Release(void) +NS_IMETHODIMP_(MozExternalRefCountType) nsTimerImpl::Release(void) { nsrefcnt count;