From c7efed20429e57831d518636a218e89c2fb58f19 Mon Sep 17 00:00:00 2001 From: "L. David Baron" Date: Thu, 13 Jun 2013 22:34:37 -0700 Subject: [PATCH 01/84] Bug 882573 patch 1: Move the style attribute style sheet from nsDocument to nsIDocument, and devirtualize its getter. r=bzbarsky --- content/base/public/nsIDocument.h | 5 ++++- content/base/src/nsDocument.h | 9 --------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/content/base/public/nsIDocument.h b/content/base/public/nsIDocument.h index 710c0ba465ec..3b130e2ffb60 100644 --- a/content/base/public/nsIDocument.h +++ b/content/base/public/nsIDocument.h @@ -766,7 +766,9 @@ public: * Get this document's inline style sheet. May return null if there * isn't one */ - virtual nsHTMLCSSStyleSheet* GetInlineStyleSheet() const = 0; + nsHTMLCSSStyleSheet* GetInlineStyleSheet() const { + return mStyleAttrStyleSheet; + } /** * Get/set the object from which a document can get a script context @@ -2178,6 +2180,7 @@ protected: nsRefPtr mCSSLoader; nsRefPtr mStyleImageLoader; nsRefPtr mAttrStyleSheet; + nsRefPtr mStyleAttrStyleSheet; // The set of all object, embed, applet, video and audio elements for // which this is the owner document. (They might not be in the document.) diff --git a/content/base/src/nsDocument.h b/content/base/src/nsDocument.h index b7e36e35eab2..fc960561824b 100644 --- a/content/base/src/nsDocument.h +++ b/content/base/src/nsDocument.h @@ -641,14 +641,6 @@ public: return mChannel; } - /** - * Get this document's inline style sheet. May return null if there - * isn't one - */ - virtual nsHTMLCSSStyleSheet* GetInlineStyleSheet() const MOZ_OVERRIDE { - return mStyleAttrStyleSheet; - } - /** * Set the object from which a document can get a script context. * This is the context within which all scripts (during document @@ -1308,7 +1300,6 @@ protected: // The channel that got passed to StartDocumentLoad(), if any nsCOMPtr mChannel; - nsRefPtr mStyleAttrStyleSheet; // A document "without a browsing context" that owns the content of // HTMLTemplateElement. From cf9ba9869ae31cf484ce3ce8ce97840742a1c3ee Mon Sep 17 00:00:00 2001 From: "L. David Baron" Date: Thu, 13 Jun 2013 22:34:37 -0700 Subject: [PATCH 02/84] Bug 882573 patch 2: Add a separate DirtyRuleProcessors method to nsStyleSet, and use it from existing methods. r=heycam --- layout/style/nsStyleSet.cpp | 36 ++++++++++++------------------------ layout/style/nsStyleSet.h | 2 ++ 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/layout/style/nsStyleSet.cpp b/layout/style/nsStyleSet.cpp index 7105db27e632..fbb373e8cbf1 100644 --- a/layout/style/nsStyleSet.cpp +++ b/layout/style/nsStyleSet.cpp @@ -423,11 +423,7 @@ nsStyleSet::AppendStyleSheet(sheetType aType, nsIStyleSheet *aSheet) if (!mSheets[aType].AppendObject(aSheet)) return NS_ERROR_OUT_OF_MEMORY; - if (!mBatching) - return GatherRuleProcessors(aType); - - mDirty |= 1 << aType; - return NS_OK; + return DirtyRuleProcessors(aType); } nsresult @@ -440,11 +436,7 @@ nsStyleSet::PrependStyleSheet(sheetType aType, nsIStyleSheet *aSheet) if (!mSheets[aType].InsertObjectAt(aSheet, 0)) return NS_ERROR_OUT_OF_MEMORY; - if (!mBatching) - return GatherRuleProcessors(aType); - - mDirty |= 1 << aType; - return NS_OK; + return DirtyRuleProcessors(aType); } nsresult @@ -454,11 +446,8 @@ nsStyleSet::RemoveStyleSheet(sheetType aType, nsIStyleSheet *aSheet) NS_ASSERTION(aSheet->IsComplete(), "Incomplete sheet being removed from style set"); mSheets[aType].RemoveObject(aSheet); - if (!mBatching) - return GatherRuleProcessors(aType); - mDirty |= 1 << aType; - return NS_OK; + return DirtyRuleProcessors(aType); } nsresult @@ -469,11 +458,7 @@ nsStyleSet::ReplaceSheets(sheetType aType, if (!mSheets[aType].AppendObjects(aNewSheets)) return NS_ERROR_OUT_OF_MEMORY; - if (!mBatching) - return GatherRuleProcessors(aType); - - mDirty |= 1 << aType; - return NS_OK; + return DirtyRuleProcessors(aType); } nsresult @@ -488,10 +473,16 @@ nsStyleSet::InsertStyleSheetBefore(sheetType aType, nsIStyleSheet *aNewSheet, int32_t idx = mSheets[aType].IndexOf(aReferenceSheet); if (idx < 0) return NS_ERROR_INVALID_ARG; - + if (!mSheets[aType].InsertObjectAt(aNewSheet, idx)) return NS_ERROR_OUT_OF_MEMORY; + return DirtyRuleProcessors(aType); +} + +nsresult +nsStyleSet::DirtyRuleProcessors(sheetType aType) +{ if (!mBatching) return GatherRuleProcessors(aType); @@ -559,11 +550,8 @@ nsStyleSet::AddDocStyleSheet(nsIStyleSheet* aSheet, nsIDocument* aDocument) } if (!sheets.InsertObjectAt(aSheet, index)) return NS_ERROR_OUT_OF_MEMORY; - if (!mBatching) - return GatherRuleProcessors(type); - mDirty |= 1 << type; - return NS_OK; + return DirtyRuleProcessors(type); } nsresult diff --git a/layout/style/nsStyleSet.h b/layout/style/nsStyleSet.h index 1a0ae8f082ce..006c0124e05d 100644 --- a/layout/style/nsStyleSet.h +++ b/layout/style/nsStyleSet.h @@ -259,6 +259,8 @@ class nsStyleSet nsresult InsertStyleSheetBefore(sheetType aType, nsIStyleSheet *aNewSheet, nsIStyleSheet *aReferenceSheet); + nsresult DirtyRuleProcessors(sheetType aType); + // Enable/Disable entire author style level (Doc, ScopedDoc & PresHint levels) bool GetAuthorStyleDisabled(); nsresult SetAuthorStyleDisabled(bool aStyleDisabled); From f753ac02c06c4f18efd2bbbe98cb81b03abf6874 Mon Sep 17 00:00:00 2001 From: "L. David Baron" Date: Thu, 13 Jun 2013 22:34:37 -0700 Subject: [PATCH 03/84] Bug 882573 patch 3: Stop putting the presentational hint and style attribute style sheets in the style set's list of style sheets; put them only in the list of rule processors. r=heycam --- content/base/src/nsDocument.cpp | 26 ++++------------------- layout/style/nsStyleSet.cpp | 37 +++++++++++++++++++++------------ layout/style/nsStyleSet.h | 3 +++ 3 files changed, 31 insertions(+), 35 deletions(-) diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 4184ba13ba47..003b5a802e6e 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -2234,12 +2234,6 @@ nsDocument::ResetStylesheetsToURI(nsIURI* aURI) // Now reset our inline style and attribute sheets. if (mAttrStyleSheet) { - // Remove this sheet from all style sets - nsCOMPtr shell = GetShell(); - if (shell) { - shell->StyleSet()->RemoveStyleSheet(nsStyleSet::ePresHintSheet, - mAttrStyleSheet); - } mAttrStyleSheet->Reset(aURI); } else { mAttrStyleSheet = new nsHTMLStyleSheet(aURI, this); @@ -2250,12 +2244,6 @@ nsDocument::ResetStylesheetsToURI(nsIURI* aURI) mAttrStyleSheet->SetOwningDocument(this); if (mStyleAttrStyleSheet) { - // Remove this sheet from all style sets - nsCOMPtr shell = GetShell(); - if (shell) { - shell->StyleSet()-> - RemoveStyleSheet(nsStyleSet::eStyleAttrSheet, mStyleAttrStyleSheet); - } mStyleAttrStyleSheet->Reset(aURI); } else { mStyleAttrStyleSheet = new nsHTMLCSSStyleSheet(aURI, this); @@ -2295,19 +2283,13 @@ void nsDocument::FillStyleSet(nsStyleSet* aStyleSet) { NS_PRECONDITION(aStyleSet, "Must have a style set"); - NS_PRECONDITION(aStyleSet->SheetCount(nsStyleSet::ePresHintSheet) == 0, - "Style set already has a preshint sheet?"); NS_PRECONDITION(aStyleSet->SheetCount(nsStyleSet::eDocSheet) == 0, "Style set already has document sheets?"); - NS_PRECONDITION(aStyleSet->SheetCount(nsStyleSet::eStyleAttrSheet) == 0, - "Style set already has style attr sheets?"); - NS_PRECONDITION(mStyleAttrStyleSheet, "No style attr stylesheet?"); - NS_PRECONDITION(mAttrStyleSheet, "No attr stylesheet?"); - aStyleSet->AppendStyleSheet(nsStyleSet::ePresHintSheet, mAttrStyleSheet); - - aStyleSet->AppendStyleSheet(nsStyleSet::eStyleAttrSheet, - mStyleAttrStyleSheet); + // We could consider moving this to nsStyleSet::Init, to match its + // handling of the eAnimationSheet and eTransitionSheet levels. + aStyleSet->DirtyRuleProcessors(nsStyleSet::ePresHintSheet); + aStyleSet->DirtyRuleProcessors(nsStyleSet::eStyleAttrSheet); int32_t i; for (i = mStyleSheets.Count() - 1; i >= 0; --i) { diff --git a/layout/style/nsStyleSet.cpp b/layout/style/nsStyleSet.cpp index fbb373e8cbf1..4f5dff656783 100644 --- a/layout/style/nsStyleSet.cpp +++ b/layout/style/nsStyleSet.cpp @@ -30,6 +30,8 @@ #include "nsStyleSheetService.h" #include "mozilla/dom/Element.h" #include "GeckoProfiler.h" +#include "nsHTMLCSSStyleSheet.h" +#include "nsHTMLStyleSheet.h" using namespace mozilla; using namespace mozilla::dom; @@ -318,19 +320,28 @@ nsStyleSet::GatherRuleProcessors(sheetType aType) // elements later if mAuthorStyleDisabled. return NS_OK; } - if (aType == eAnimationSheet) { - // We have no sheet for the animations level; just a rule - // processor. (XXX: We should probably do this for the other - // non-CSS levels too!) - mRuleProcessors[aType] = PresContext()->AnimationManager(); - return NS_OK; - } - if (aType == eTransitionSheet) { - // We have no sheet for the transitions level; just a rule - // processor. (XXX: We should probably do this for the other - // non-CSS levels too!) - mRuleProcessors[aType] = PresContext()->TransitionManager(); - return NS_OK; + switch (aType) { + // handle the types for which have a rule processor that does not + // implement the style sheet interface. + case eAnimationSheet: + MOZ_ASSERT(mSheets[aType].Count() == 0); + mRuleProcessors[aType] = PresContext()->AnimationManager(); + return NS_OK; + case eTransitionSheet: + MOZ_ASSERT(mSheets[aType].Count() == 0); + mRuleProcessors[aType] = PresContext()->TransitionManager(); + return NS_OK; + case eStyleAttrSheet: + MOZ_ASSERT(mSheets[aType].Count() == 0); + mRuleProcessors[aType] = PresContext()->Document()->GetInlineStyleSheet(); + return NS_OK; + case ePresHintSheet: + MOZ_ASSERT(mSheets[aType].Count() == 0); + mRuleProcessors[aType] = PresContext()->Document()->GetAttributeStyleSheet(); + return NS_OK; + default: + // keep going + break; } if (aType == eScopedDocSheet) { // Create a rule processor for each scope. diff --git a/layout/style/nsStyleSet.h b/layout/style/nsStyleSet.h index 006c0124e05d..1e46261d5a4b 100644 --- a/layout/style/nsStyleSet.h +++ b/layout/style/nsStyleSet.h @@ -394,6 +394,9 @@ class nsStyleSet // The sheets in each array in mSheets are stored with the most significant // sheet last. + // The arrays for ePresHintSheet, eStyleAttrSheet, eTransitionSheet, + // and eAnimationSheet are always empty. (FIXME: We should reduce + // the storage needed for them.) nsCOMArray mSheets[eSheetTypeCount]; // mRuleProcessors[eScopedDocSheet] is always null; rule processors From d8bcb54fbd1d9f88ff8a82106f09c840dc59f079 Mon Sep 17 00:00:00 2001 From: "L. David Baron" Date: Thu, 13 Jun 2013 22:34:37 -0700 Subject: [PATCH 04/84] Bug 882573 patch 4: Make nsHTMLStyleSheet and nsHTMLCSSStyleSheet stop implementing nsIStyleSheet. r=heycam Note that this removes the Reset method and the mURL and mDocument members (and arguments to set them) from nsHTMLCSSStyleSheet. On the other hand, from nsHTMLStyleSheet it only removes mURL (and equivalent arguments), and nsHTMLStyleSheet keeps the SetOwningDocument method that was previously part of nsIStyleSheet (but no longer virtual). --- content/base/src/nsDocument.cpp | 21 ++---- layout/style/nsHTMLCSSStyleSheet.cpp | 105 +-------------------------- layout/style/nsHTMLCSSStyleSheet.h | 32 +------- layout/style/nsHTMLStyleSheet.cpp | 96 ++---------------------- layout/style/nsHTMLStyleSheet.h | 27 ++----- 5 files changed, 19 insertions(+), 262 deletions(-) diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 003b5a802e6e..6014b96e49c6 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -1478,8 +1478,6 @@ nsDocument::~nsDocument() if (mAttrStyleSheet) { mAttrStyleSheet->SetOwningDocument(nullptr); } - if (mStyleAttrStyleSheet) - mStyleAttrStyleSheet->SetOwningDocument(nullptr); if (mListenerManager) { mListenerManager->Disconnect(); @@ -2234,25 +2232,16 @@ nsDocument::ResetStylesheetsToURI(nsIURI* aURI) // Now reset our inline style and attribute sheets. if (mAttrStyleSheet) { - mAttrStyleSheet->Reset(aURI); + mAttrStyleSheet->Reset(); + mAttrStyleSheet->SetOwningDocument(this); } else { - mAttrStyleSheet = new nsHTMLStyleSheet(aURI, this); + mAttrStyleSheet = new nsHTMLStyleSheet(this); } - // Don't use AddStyleSheet, since it'll put the sheet into style - // sets in the document level, which is not desirable here. - mAttrStyleSheet->SetOwningDocument(this); - - if (mStyleAttrStyleSheet) { - mStyleAttrStyleSheet->Reset(aURI); - } else { - mStyleAttrStyleSheet = new nsHTMLCSSStyleSheet(aURI, this); + if (!mStyleAttrStyleSheet) { + mStyleAttrStyleSheet = new nsHTMLCSSStyleSheet(); } - // The loop over style sets below will handle putting this sheet - // into style sets as needed. - mStyleAttrStyleSheet->SetOwningDocument(this); - // Now set up our style sets nsCOMPtr shell = GetShell(); if (shell) { diff --git a/layout/style/nsHTMLCSSStyleSheet.cpp b/layout/style/nsHTMLCSSStyleSheet.cpp index 1c93aceefcf7..c3d3882b8bd0 100644 --- a/layout/style/nsHTMLCSSStyleSheet.cpp +++ b/layout/style/nsHTMLCSSStyleSheet.cpp @@ -39,12 +39,8 @@ ClearAttrCache(const nsAString& aKey, MiscContainer*& aValue, void*) } // anonymous namespace -nsHTMLCSSStyleSheet::nsHTMLCSSStyleSheet(nsIURI* aURL, nsIDocument* aDocument) - : mURL(aURL) - , mDocument(aDocument) // not refcounted! +nsHTMLCSSStyleSheet::nsHTMLCSSStyleSheet() { - MOZ_ASSERT(aURL); - MOZ_ASSERT(aDocument); mCachedStyleAttrs.Init(); } @@ -55,9 +51,7 @@ nsHTMLCSSStyleSheet::~nsHTMLCSSStyleSheet() mCachedStyleAttrs.Enumerate(ClearAttrCache, nullptr); } -NS_IMPL_ISUPPORTS2(nsHTMLCSSStyleSheet, - nsIStyleSheet, - nsIStyleRuleProcessor) +NS_IMPL_ISUPPORTS1(nsHTMLCSSStyleSheet, nsIStyleRuleProcessor) /* virtual */ void nsHTMLCSSStyleSheet::RulesMatching(ElementRuleProcessorData* aData) @@ -175,98 +169,3 @@ nsHTMLCSSStyleSheet::LookupStyleAttr(const nsAString& aSerialized) { return mCachedStyleAttrs.Get(aSerialized); } - -void -nsHTMLCSSStyleSheet::Reset(nsIURI* aURL) -{ - mURL = aURL; -} - -/* virtual */ nsIURI* -nsHTMLCSSStyleSheet::GetSheetURI() const -{ - return mURL; -} - -/* virtual */ nsIURI* -nsHTMLCSSStyleSheet::GetBaseURI() const -{ - return mURL; -} - -/* virtual */ void -nsHTMLCSSStyleSheet::GetTitle(nsString& aTitle) const -{ - aTitle.AssignLiteral("Internal HTML/CSS Style Sheet"); -} - -/* virtual */ void -nsHTMLCSSStyleSheet::GetType(nsString& aType) const -{ - aType.AssignLiteral("text/html"); -} - -/* virtual */ bool -nsHTMLCSSStyleSheet::HasRules() const -{ - // Say we always have rules, since we don't know. - return true; -} - -/* virtual */ bool -nsHTMLCSSStyleSheet::IsApplicable() const -{ - return true; -} - -/* virtual */ void -nsHTMLCSSStyleSheet::SetEnabled(bool aEnabled) -{ // these can't be disabled -} - -/* virtual */ bool -nsHTMLCSSStyleSheet::IsComplete() const -{ - return true; -} - -/* virtual */ void -nsHTMLCSSStyleSheet::SetComplete() -{ -} - -// style sheet owner info -/* virtual */ nsIStyleSheet* -nsHTMLCSSStyleSheet::GetParentSheet() const -{ - return nullptr; -} - -/* virtual */ nsIDocument* -nsHTMLCSSStyleSheet::GetOwningDocument() const -{ - return mDocument; -} - -/* virtual */ void -nsHTMLCSSStyleSheet::SetOwningDocument(nsIDocument* aDocument) -{ - mDocument = aDocument; -} - -#ifdef DEBUG -/* virtual */ void -nsHTMLCSSStyleSheet::List(FILE* out, int32_t aIndent) const -{ - // Indent - for (int32_t index = aIndent; --index >= 0; ) fputs(" ", out); - - fputs("HTML CSS Style Sheet: ", out); - nsAutoCString urlSpec; - mURL->GetSpec(urlSpec); - if (!urlSpec.IsEmpty()) { - fputs(urlSpec.get(), out); - } - fputs("\n", out); -} -#endif diff --git a/layout/style/nsHTMLCSSStyleSheet.h b/layout/style/nsHTMLCSSStyleSheet.h index 9336ad83da00..b3e8a16c6fe2 100644 --- a/layout/style/nsHTMLCSSStyleSheet.h +++ b/layout/style/nsHTMLCSSStyleSheet.h @@ -19,34 +19,14 @@ struct MiscContainer; -class nsHTMLCSSStyleSheet MOZ_FINAL : public nsIStyleSheet, - public nsIStyleRuleProcessor +class nsHTMLCSSStyleSheet MOZ_FINAL : public nsIStyleRuleProcessor { public: - nsHTMLCSSStyleSheet(nsIURI* aURL, nsIDocument* aDocument); + nsHTMLCSSStyleSheet(); ~nsHTMLCSSStyleSheet(); NS_DECL_ISUPPORTS - void Reset(nsIURI* aURL); - - // nsIStyleSheet - virtual nsIURI* GetSheetURI() const MOZ_OVERRIDE; - virtual nsIURI* GetBaseURI() const MOZ_OVERRIDE; - virtual void GetTitle(nsString& aTitle) const MOZ_OVERRIDE; - virtual void GetType(nsString& aType) const MOZ_OVERRIDE; - virtual bool HasRules() const MOZ_OVERRIDE; - virtual bool IsApplicable() const MOZ_OVERRIDE; - virtual void SetEnabled(bool aEnabled) MOZ_OVERRIDE; - virtual bool IsComplete() const MOZ_OVERRIDE; - virtual void SetComplete() MOZ_OVERRIDE; - virtual nsIStyleSheet* GetParentSheet() const MOZ_OVERRIDE; // will be null - virtual nsIDocument* GetOwningDocument() const MOZ_OVERRIDE; - virtual void SetOwningDocument(nsIDocument* aDocument) MOZ_OVERRIDE; -#ifdef DEBUG - virtual void List(FILE* out = stdout, int32_t aIndent = 0) const MOZ_OVERRIDE; -#endif - // nsIStyleRuleProcessor virtual void RulesMatching(ElementRuleProcessorData* aData) MOZ_OVERRIDE; virtual void RulesMatching(PseudoElementRuleProcessorData* aData) MOZ_OVERRIDE; @@ -73,15 +53,7 @@ private: nsHTMLCSSStyleSheet& operator=(const nsHTMLCSSStyleSheet& aCopy) MOZ_DELETE; protected: - nsCOMPtr mURL; - nsIDocument* mDocument; nsDataHashtable mCachedStyleAttrs; }; -inline nsISupports* -ToSupports(nsHTMLCSSStyleSheet* aPointer) -{ - return static_cast(aPointer); -} - #endif /* !defined(nsHTMLCSSStyleSheet_h_) */ diff --git a/layout/style/nsHTMLStyleSheet.cpp b/layout/style/nsHTMLStyleSheet.cpp index d1ef8c23347c..e91f71da60ad 100644 --- a/layout/style/nsHTMLStyleSheet.cpp +++ b/layout/style/nsHTMLStyleSheet.cpp @@ -227,13 +227,11 @@ static PLDHashTableOps LangRuleTable_Ops = { // ----------------------------------------------------------- -nsHTMLStyleSheet::nsHTMLStyleSheet(nsIURI* aURL, nsIDocument* aDocument) - : mURL(aURL) - , mDocument(aDocument) +nsHTMLStyleSheet::nsHTMLStyleSheet(nsIDocument* aDocument) + : mDocument(aDocument) , mTableQuirkColorRule(new TableQuirkColorRule()) , mTableTHRule(new TableTHRule()) { - MOZ_ASSERT(aURL); MOZ_ASSERT(aDocument); mMappedAttrTable.ops = nullptr; mLangRuleTable.ops = nullptr; @@ -247,7 +245,7 @@ nsHTMLStyleSheet::~nsHTMLStyleSheet() PL_DHashTableFinish(&mMappedAttrTable); } -NS_IMPL_ISUPPORTS2(nsHTMLStyleSheet, nsIStyleSheet, nsIStyleRuleProcessor) +NS_IMPL_ISUPPORTS1(nsHTMLStyleSheet, nsIStyleRuleProcessor) /* virtual */ void nsHTMLStyleSheet::RulesMatching(ElementRuleProcessorData* aData) @@ -402,82 +400,15 @@ nsHTMLStyleSheet::RulesMatching(XULTreeRuleProcessorData* aData) } #endif - // nsIStyleSheet api -/* virtual */ nsIURI* -nsHTMLStyleSheet::GetSheetURI() const -{ - return mURL; -} - -/* virtual */ nsIURI* -nsHTMLStyleSheet::GetBaseURI() const -{ - return mURL; -} - -/* virtual */ void -nsHTMLStyleSheet::GetTitle(nsString& aTitle) const -{ - aTitle.Truncate(); -} - -/* virtual */ void -nsHTMLStyleSheet::GetType(nsString& aType) const -{ - aType.AssignLiteral("text/html"); -} - -/* virtual */ bool -nsHTMLStyleSheet::HasRules() const -{ - return true; // We have rules at all reasonable times -} - -/* virtual */ bool -nsHTMLStyleSheet::IsApplicable() const -{ - return true; -} - -/* virtual */ void -nsHTMLStyleSheet::SetEnabled(bool aEnabled) -{ // these can't be disabled -} - -/* virtual */ bool -nsHTMLStyleSheet::IsComplete() const -{ - return true; -} - -/* virtual */ void -nsHTMLStyleSheet::SetComplete() -{ -} - -/* virtual */ nsIStyleSheet* -nsHTMLStyleSheet::GetParentSheet() const -{ - return nullptr; -} - -/* virtual */ nsIDocument* -nsHTMLStyleSheet::GetOwningDocument() const -{ - return mDocument; -} - -/* virtual */ void +void nsHTMLStyleSheet::SetOwningDocument(nsIDocument* aDocument) { mDocument = aDocument; // not refcounted } void -nsHTMLStyleSheet::Reset(nsIURI* aURL) +nsHTMLStyleSheet::Reset() { - mURL = aURL; - mLinkRule = nullptr; mVisitedRule = nullptr; mActiveRule = nullptr; @@ -594,23 +525,6 @@ nsHTMLStyleSheet::LangRuleFor(const nsString& aLanguage) return entry->mRule; } -#ifdef DEBUG -/* virtual */ void -nsHTMLStyleSheet::List(FILE* out, int32_t aIndent) const -{ - // Indent - for (int32_t index = aIndent; --index >= 0; ) fputs(" ", out); - - fputs("HTML Style Sheet: ", out); - nsAutoCString urlSpec; - mURL->GetSpec(urlSpec); - if (!urlSpec.IsEmpty()) { - fputs(urlSpec.get(), out); - } - fputs("\n", out); -} -#endif - static size_t SizeOfAttributesEntryExcludingThis(PLDHashEntryHdr* aEntry, nsMallocSizeOfFun aMallocSizeOf, diff --git a/layout/style/nsHTMLStyleSheet.h b/layout/style/nsHTMLStyleSheet.h index c56b4bfa4cfb..886745df66e7 100644 --- a/layout/style/nsHTMLStyleSheet.h +++ b/layout/style/nsHTMLStyleSheet.h @@ -24,31 +24,15 @@ class nsMappedAttributes; -class nsHTMLStyleSheet MOZ_FINAL : public nsIStyleSheet, - public nsIStyleRuleProcessor +class nsHTMLStyleSheet MOZ_FINAL : public nsIStyleRuleProcessor { public: - nsHTMLStyleSheet(nsIURI* aURL, nsIDocument* aDocument); + nsHTMLStyleSheet(nsIDocument* aDocument); + + void SetOwningDocument(nsIDocument* aDocument); NS_DECL_ISUPPORTS - // nsIStyleSheet api - virtual nsIURI* GetSheetURI() const MOZ_OVERRIDE; - virtual nsIURI* GetBaseURI() const MOZ_OVERRIDE; - virtual void GetTitle(nsString& aTitle) const MOZ_OVERRIDE; - virtual void GetType(nsString& aType) const MOZ_OVERRIDE; - virtual bool HasRules() const MOZ_OVERRIDE; - virtual bool IsApplicable() const MOZ_OVERRIDE; - virtual void SetEnabled(bool aEnabled) MOZ_OVERRIDE; - virtual bool IsComplete() const MOZ_OVERRIDE; - virtual void SetComplete() MOZ_OVERRIDE; - virtual nsIStyleSheet* GetParentSheet() const MOZ_OVERRIDE; // will be null - virtual nsIDocument* GetOwningDocument() const MOZ_OVERRIDE; - virtual void SetOwningDocument(nsIDocument* aDocumemt) MOZ_OVERRIDE; -#ifdef DEBUG - virtual void List(FILE* out = stdout, int32_t aIndent = 0) const MOZ_OVERRIDE; -#endif - // nsIStyleRuleProcessor API virtual void RulesMatching(ElementRuleProcessorData* aData) MOZ_OVERRIDE; virtual void RulesMatching(PseudoElementRuleProcessorData* aData) MOZ_OVERRIDE; @@ -67,7 +51,7 @@ public: const MOZ_MUST_OVERRIDE MOZ_OVERRIDE; size_t DOMSizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const; - void Reset(nsIURI* aURL); + void Reset(); nsresult SetLinkColor(nscolor aColor); nsresult SetActiveLinkColor(nscolor aColor); nsresult SetVisitedLinkColor(nscolor aColor); @@ -159,7 +143,6 @@ public: // for mLangRuleTable structures only }; private: - nsCOMPtr mURL; nsIDocument* mDocument; nsRefPtr mLinkRule; nsRefPtr mVisitedRule; From 56c8dc207993a3dde409c5ae6dbf70cfcd7f3f71 Mon Sep 17 00:00:00 2001 From: Julian Seward Date: Fri, 14 Jun 2013 08:09:20 +0200 Subject: [PATCH 05/84] Bug 863475 - integrate ARM EXIDX unwind parsing into Breakpad. r=glandium,ted --- .../crashreporter/google-breakpad/Makefile.am | 6 + .../google-breakpad/src/common/Makefile.in | 2 + .../src/common/arm_ex_reader.cc | 502 ++++++++++++++++++ .../src/common/arm_ex_reader.h | 115 ++++ .../src/common/arm_ex_to_module.cc | 206 +++++++ .../src/common/arm_ex_to_module.h | 129 +++++ .../src/common/linux/dump_symbols.cc | 74 +++ .../google-breakpad/src/common/module.cc | 2 +- .../google-breakpad/src/common/module.h | 9 +- .../google-breakpad/src/common/moz.build | 2 + .../src/common/unique_string.h | 21 + .../src/processor/cfi_frame_info.cc | 6 +- 12 files changed, 1069 insertions(+), 5 deletions(-) create mode 100644 toolkit/crashreporter/google-breakpad/src/common/arm_ex_reader.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/arm_ex_reader.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/arm_ex_to_module.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/arm_ex_to_module.h diff --git a/toolkit/crashreporter/google-breakpad/Makefile.am b/toolkit/crashreporter/google-breakpad/Makefile.am index 8649816f79cd..61fcc7b9cc21 100644 --- a/toolkit/crashreporter/google-breakpad/Makefile.am +++ b/toolkit/crashreporter/google-breakpad/Makefile.am @@ -433,6 +433,8 @@ src_tools_linux_dump_syms_dump_syms_SOURCES = \ src/common/dwarf/bytereader.cc \ src/common/dwarf/dwarf2diehandler.cc \ src/common/dwarf/dwarf2reader.cc \ + src/common/arm_ex_reader.cc \ + src/common/arm_ex_to_module.cc \ src/common/linux/dump_symbols.cc \ src/common/linux/elf_symbols_to_module.cc \ src/common/linux/elfutils.cc \ @@ -1015,6 +1017,10 @@ EXTRA_DIST = \ src/common/convert_UTF.h \ src/common/linux/dump_symbols.cc \ src/common/linux/dump_symbols.h \ + src/common/arm_ex_reader.cc \ + src/common/arm_ex_reader.h \ + src/common/arm_ex_to_module.cc \ + src/common/arm_ex_to_module.h \ src/common/linux/elf_symbols_to_module.cc \ src/common/linux/elf_symbols_to_module.h \ src/common/linux/elfutils.cc \ diff --git a/toolkit/crashreporter/google-breakpad/src/common/Makefile.in b/toolkit/crashreporter/google-breakpad/src/common/Makefile.in index c607793f423b..d7f070133067 100644 --- a/toolkit/crashreporter/google-breakpad/src/common/Makefile.in +++ b/toolkit/crashreporter/google-breakpad/src/common/Makefile.in @@ -32,6 +32,8 @@ HOST_CPPSRCS = \ stabs_to_module.cc \ stabs_reader.cc \ dwarf_line_to_module.cc \ + arm_ex_reader.cc \ + arm_ex_to_module.cc \ pathname_stripper.cc \ logging.cc \ $(NULL) diff --git a/toolkit/crashreporter/google-breakpad/src/common/arm_ex_reader.cc b/toolkit/crashreporter/google-breakpad/src/common/arm_ex_reader.cc new file mode 100644 index 000000000000..5d87ab40906c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/arm_ex_reader.cc @@ -0,0 +1,502 @@ + +/* libunwind - a platform-independent unwind library + Copyright 2011 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Derived from libunwind, with extensive modifications. + + +#include "common/arm_ex_reader.h" +#include "common/logging.h" + +#include + +// This file, in conjunction with arm_ex_to_module.cc, translates +// EXIDX unwind information into the same format that Breakpad uses +// for CFI information. Hence Breakpad's CFI unwinding abilities +// also become usable for EXIDX. +// +// See: "Exception Handling ABI for the ARM Architecture", ARM IHI 0038A +// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038a/IHI0038A_ehabi.pdf + +// EXIDX data is presented in two parts: +// +// * an index table. This contains two words per routine, +// the first of which identifies the routine, and the second +// of which is a reference to the unwind bytecode. If the +// bytecode is very compact -- 3 bytes or less -- it can be +// stored directly in the second word. +// +// * an area containing the unwind bytecodes. + +// General flow is: ExceptionTableInfo::Start iterates over all +// of the index table entries (pairs). For each entry, it: +// +// * calls ExceptionTableInfo::ExtabEntryExtract to copy the bytecode +// out into an intermediate buffer. + +// * uses ExceptionTableInfo::ExtabEntryDecode to parse the intermediate +// buffer. Each bytecode instruction is bundled into a +// arm_ex_to_module::extab_data structure, and handed to .. +// +// * .. ARMExToModule::ImproveStackFrame, which in turn hands it to +// ARMExToModule::TranslateCmd, and that generates the pseudo-CFI +// records that Breakpad stores. + +#define ARM_EXIDX_CANT_UNWIND 0x00000001 +#define ARM_EXIDX_COMPACT 0x80000000 +#define ARM_EXTBL_OP_FINISH 0xb0 +#define ARM_EXIDX_TABLE_LIMIT (255*4) + +namespace arm_ex_reader { + +using arm_ex_to_module::ARM_EXIDX_CMD_FINISH; +using arm_ex_to_module::ARM_EXIDX_CMD_SUB_FROM_VSP; +using arm_ex_to_module::ARM_EXIDX_CMD_ADD_TO_VSP; +using arm_ex_to_module::ARM_EXIDX_CMD_REG_POP; +using arm_ex_to_module::ARM_EXIDX_CMD_REG_TO_SP; +using arm_ex_to_module::ARM_EXIDX_CMD_VFP_POP; +using arm_ex_to_module::ARM_EXIDX_CMD_WREG_POP; +using arm_ex_to_module::ARM_EXIDX_CMD_WCGR_POP; +using arm_ex_to_module::ARM_EXIDX_CMD_RESERVED; +using arm_ex_to_module::ARM_EXIDX_CMD_REFUSED; +using arm_ex_to_module::exidx_entry; +using arm_ex_to_module::ARM_EXIDX_VFP_SHIFT_16; +using arm_ex_to_module::ARM_EXIDX_VFP_FSTMD; +using google_breakpad::MemoryRange; + + +static void* Prel31ToAddr(const void* addr) +{ + uint32_t offset32 = *reinterpret_cast(addr); + // sign extend offset32[30:0] to 64 bits -- copy bit 30 to positions + // 63:31 inclusive. + uint64_t offset64 = offset32; + if (offset64 & (1ULL << 30)) + offset64 |= 0xFFFFFFFF80000000ULL; + else + offset64 &= 0x000000007FFFFFFFULL; + return ((char*)addr) + (uintptr_t)offset64; +} + + +// Extract unwind bytecode for the function denoted by |entry| into |buf|, +// and return the number of bytes of |buf| written, along with a code +// indicating the outcome. + +ExceptionTableInfo::ExExtractResult +ExceptionTableInfo::ExtabEntryExtract(const struct exidx_entry* entry, + uint8_t* buf, size_t buf_size, + /*OUT*/size_t* buf_used) +{ + MemoryRange mr_out(buf, buf_size); + + *buf_used = 0; + +# define PUT_BUF_U8(_byte) \ + do { if (!mr_out.Covers(*buf_used, 1)) return ExOutBufOverflow; \ + buf[(*buf_used)++] = (_byte); } while (0) + +# define GET_EX_U32(_lval, _addr, _sec_mr) \ + do { if (!(_sec_mr).Covers(reinterpret_cast(_addr) \ + - (_sec_mr).data(), 4)) \ + return ExInBufOverflow; \ + (_lval) = *(reinterpret_cast(_addr)); } while (0) + +# define GET_EXIDX_U32(_lval, _addr) \ + GET_EX_U32(_lval, _addr, mr_exidx_) +# define GET_EXTAB_U32(_lval, _addr) \ + GET_EX_U32(_lval, _addr, mr_extab_) + + uint32_t data; + GET_EXIDX_U32(data, &entry->data); + + // A function can be marked CANT_UNWIND if (eg) it is known to be + // at the bottom of the stack. + if (data == ARM_EXIDX_CANT_UNWIND) + return ExCantUnwind; + + uint32_t pers; // personality number + uint32_t extra; // number of extra data words required + uint32_t extra_allowed; // number of extra data words allowed + uint32_t* extbl_data; // the handler entry, if not inlined + + if (data & ARM_EXIDX_COMPACT) { + // The handler table entry has been inlined into the index table entry. + // In this case it can only be an ARM-defined compact model, since + // bit 31 is 1. Only personalities 0, 1 and 2 are defined for the + // ARM compact model, but 1 and 2 are "Long format" and may require + // extra data words. Hence the allowable personalities here are: + // personality 0, in which case 'extra' has no meaning + // personality 1, with zero extra words + // personality 2, with zero extra words + extbl_data = NULL; + pers = (data >> 24) & 0x0F; + extra = (data >> 16) & 0xFF; + extra_allowed = 0; + } + else { + // The index table entry is a pointer to the handler entry. Note + // that Prel31ToAddr will read the given address, but we already + // range-checked above. + extbl_data = reinterpret_cast(Prel31ToAddr(&entry->data)); + GET_EXTAB_U32(data, extbl_data); + if (!(data & ARM_EXIDX_COMPACT)) { + // This denotes a "generic model" handler. That will involve + // executing arbitary machine code, which is something we + // can't represent here; hence reject it. + return ExCantRepresent; + } + // So we have a compact model representation. Again, 3 possible + // personalities, but this time up to 255 allowable extra words. + pers = (data >> 24) & 0x0F; + extra = (data >> 16) & 0xFF; + extra_allowed = 255; + extbl_data++; + } + + // Now look at the the handler table entry. The first word is + // |data| and subsequent words start at |*extbl_data|. The number + // of extra words to use is |extra|, provided that the personality + // allows extra words. Even if it does, none may be available -- + // extra_allowed is the maximum number of extra words allowed. */ + if (pers == 0) { + // "Su16" in the documentation -- 3 unwinding insn bytes + // |extra| has no meaning here; instead that byte is an unwind-info byte + PUT_BUF_U8(data >> 16); + PUT_BUF_U8(data >> 8); + PUT_BUF_U8(data); + } + else if ((pers == 1 || pers == 2) && extra <= extra_allowed) { + // "Lu16" or "Lu32" respectively -- 2 unwinding insn bytes, + // and up to 255 extra words. + PUT_BUF_U8(data >> 8); + PUT_BUF_U8(data); + for (uint32_t j = 0; j < extra; j++) { + GET_EXTAB_U32(data, extbl_data); + extbl_data++; + PUT_BUF_U8(data >> 24); + PUT_BUF_U8(data >> 16); + PUT_BUF_U8(data >> 8); + PUT_BUF_U8(data >> 0); + } + } + else { + // The entry is invalid. + return ExInvalid; + } + + // Make sure the entry is terminated with "FINISH" + if (*buf_used > 0 && buf[(*buf_used) - 1] != ARM_EXTBL_OP_FINISH) + PUT_BUF_U8(ARM_EXTBL_OP_FINISH); + + return ExSuccess; + +# undef GET_EXTAB_U32 +# undef GET_EXIDX_U32 +# undef GET_U32 +# undef PUT_BUF_U8 +} + + +// Take the unwind information extracted by ExtabEntryExtract +// and parse it into frame-unwind instructions. These are as +// specified in "Table 4, ARM-defined frame-unwinding instructions" +// in the specification document detailed in comments at the top +// of this file. +// +// This reads from |buf[0, +data_size)|. It checks for overruns of +// the input buffer and returns a negative value if that happens, or +// for any other failure cases. It returns zero in case of success. +int ExceptionTableInfo::ExtabEntryDecode(const uint8_t* buf, size_t buf_size) +{ + if (buf == NULL || buf_size == 0) + return -1; + + MemoryRange mr_in(buf, buf_size); + const uint8_t* buf_initially = buf; + +# define GET_BUF_U8(_lval) \ + do { if (!mr_in.Covers(buf - buf_initially, 1)) return -1; \ + (_lval) = *(buf++); } while (0) + + const uint8_t* end = buf + buf_size; + + while (buf < end) { + struct arm_ex_to_module::extab_data edata; + memset(&edata, 0, sizeof(edata)); + + uint8_t op; + GET_BUF_U8(op); + if ((op & 0xc0) == 0x00) { + // vsp = vsp + (xxxxxx << 2) + 4 + edata.cmd = ARM_EXIDX_CMD_ADD_TO_VSP; + edata.data = (((int)op & 0x3f) << 2) + 4; + } + else if ((op & 0xc0) == 0x40) { + // vsp = vsp - (xxxxxx << 2) - 4 + edata.cmd = ARM_EXIDX_CMD_SUB_FROM_VSP; + edata.data = (((int)op & 0x3f) << 2) + 4; + } + else if ((op & 0xf0) == 0x80) { + uint8_t op2; + GET_BUF_U8(op2); + if (op == 0x80 && op2 == 0x00) { + // Refuse to unwind + edata.cmd = ARM_EXIDX_CMD_REFUSED; + } else { + // Pop up to 12 integer registers under masks {r15-r12},{r11-r4} + edata.cmd = ARM_EXIDX_CMD_REG_POP; + edata.data = ((op & 0xf) << 8) | op2; + edata.data = edata.data << 4; + } + } + else if ((op & 0xf0) == 0x90) { + if (op == 0x9d || op == 0x9f) { + // 9d: Reserved as prefix for ARM register to register moves + // 9f: Reserved as perfix for Intel Wireless MMX reg to reg moves + edata.cmd = ARM_EXIDX_CMD_RESERVED; + } else { + // Set vsp = r[nnnn] + edata.cmd = ARM_EXIDX_CMD_REG_TO_SP; + edata.data = op & 0x0f; + } + } + else if ((op & 0xf0) == 0xa0) { + // Pop r4 to r[4+nnn], or + // Pop r4 to r[4+nnn] and r14 or + unsigned end = (op & 0x07); + edata.data = (1 << (end + 1)) - 1; + edata.data = edata.data << 4; + if (op & 0x08) edata.data |= 1 << 14; + edata.cmd = ARM_EXIDX_CMD_REG_POP; + } + else if (op == ARM_EXTBL_OP_FINISH) { + // Finish + edata.cmd = ARM_EXIDX_CMD_FINISH; + buf = end; + } + else if (op == 0xb1) { + uint8_t op2; + GET_BUF_U8(op2); + if (op2 == 0 || (op2 & 0xf0)) { + // Spare + edata.cmd = ARM_EXIDX_CMD_RESERVED; + } else { + // Pop integer registers under mask {r3,r2,r1,r0} + edata.cmd = ARM_EXIDX_CMD_REG_POP; + edata.data = op2 & 0x0f; + } + } + else if (op == 0xb2) { + // vsp = vsp + 0x204 + (uleb128 << 2) + uint64_t offset = 0; + uint8_t byte, shift = 0; + do { + GET_BUF_U8(byte); + offset |= (byte & 0x7f) << shift; + shift += 7; + } while ((byte & 0x80) && buf < end); + edata.data = offset * 4 + 0x204; + edata.cmd = ARM_EXIDX_CMD_ADD_TO_VSP; + } + else if (op == 0xb3 || op == 0xc8 || op == 0xc9) { + // b3: Pop VFP regs D[ssss] to D[ssss+cccc], FSTMFDX-ishly + // c8: Pop VFP regs D[16+ssss] to D[16+ssss+cccc], FSTMFDD-ishly + // c9: Pop VFP regs D[ssss] to D[ssss+cccc], FSTMFDD-ishly + edata.cmd = ARM_EXIDX_CMD_VFP_POP; + GET_BUF_U8(edata.data); + if (op == 0xc8) edata.data |= ARM_EXIDX_VFP_SHIFT_16; + if (op != 0xb3) edata.data |= ARM_EXIDX_VFP_FSTMD; + } + else if ((op & 0xf8) == 0xb8 || (op & 0xf8) == 0xd0) { + // b8: Pop VFP regs D[8] to D[8+nnn], FSTMFDX-ishly + // d0: Pop VFP regs D[8] to D[8+nnn], FSTMFDD-ishly + edata.cmd = ARM_EXIDX_CMD_VFP_POP; + edata.data = 0x80 | (op & 0x07); + if ((op & 0xf8) == 0xd0) edata.data |= ARM_EXIDX_VFP_FSTMD; + } + else if (op >= 0xc0 && op <= 0xc5) { + // Intel Wireless MMX pop wR[10]-wr[10+nnn], nnn != 6,7 + edata.cmd = ARM_EXIDX_CMD_WREG_POP; + edata.data = 0xa0 | (op & 0x07); + } + else if (op == 0xc6) { + // Intel Wireless MMX pop wR[ssss] to wR[ssss+cccc] + edata.cmd = ARM_EXIDX_CMD_WREG_POP; + GET_BUF_U8(edata.data); + } + else if (op == 0xc7) { + uint8_t op2; + GET_BUF_U8(op2); + if (op2 == 0 || (op2 & 0xf0)) { + // Spare + edata.cmd = ARM_EXIDX_CMD_RESERVED; + } else { + // Intel Wireless MMX pop wCGR registers under mask {wCGR3,2,1,0} + edata.cmd = ARM_EXIDX_CMD_WCGR_POP; + edata.data = op2 & 0x0f; + } + } + else { + // Spare + edata.cmd = ARM_EXIDX_CMD_RESERVED; + } + + int ret = handler_->ImproveStackFrame(&edata); + if (ret < 0) return ret; + } + return 0; + +# undef GET_BUF_U8 +} + +void ExceptionTableInfo::Start() +{ + const struct exidx_entry* start + = reinterpret_cast(mr_exidx_.data()); + const struct exidx_entry* end + = reinterpret_cast(mr_exidx_.data() + + mr_exidx_.length()); + + // Iterate over each of the EXIDX entries (pairs of 32-bit words). + // These occupy the entire .exidx section. + for (const struct exidx_entry* entry = start; entry < end; ++entry) { + + // Figure out the code address range that this table entry is + // associated with. + uint32_t addr = (reinterpret_cast(Prel31ToAddr(&entry->addr)) + - mapping_addr_ + loading_addr_) & 0x7fffffff; + uint32_t next_addr; + if (entry < end - 1) + next_addr = (reinterpret_cast(Prel31ToAddr(&((entry + 1)->addr))) + - mapping_addr_ + loading_addr_) & 0x7fffffff; + else { + // This is the last EXIDX entry in the sequence, so we don't + // have an address for the start of the next function, to limit + // this one. Instead use the address of the last byte of the + // text section associated with this .exidx section, that we + // have been given. So as to avoid junking up the CFI unwind + // tables with absurdly large address ranges in the case where + // text_last_svma_ is wrong, only use the value if it is nonzero + // and within one page of |addr|. Otherwise assume a length of 1. + // + // In some cases, gcc has been observed to finish the exidx + // section with an entry of length 1 marked CANT_UNWIND, + // presumably exactly for the purpose of giving a definite + // length for the last real entry, without having to look at + // text segment boundaries. + bool plausible = false; + next_addr = addr + 1; + if (text_last_svma_ != 0) { + uint32_t maybe_next_addr = text_last_svma_ + 1; + if (maybe_next_addr > addr && maybe_next_addr - addr <= 4096) { + next_addr = maybe_next_addr; + plausible = true; + } + } + if (!plausible) + BPLOG(INFO) << "ExceptionTableInfo: implausible EXIDX last entry size " + << (int32_t)(text_last_svma_ - addr) + << "; using 1 instead."; + } + + // Extract the unwind info into |buf|. This might fail for + // various reasons. It involves reading both the .exidx and + // .extab sections. All accesses to those sections are + // bounds-checked. + uint8_t buf[ARM_EXIDX_TABLE_LIMIT]; + size_t buf_used = 0; + ExExtractResult res = ExtabEntryExtract(entry, buf, sizeof(buf), &buf_used); + if (res != ExSuccess) { + // Couldn't extract the unwind info, for some reason. Move on. + switch (res) { + case ExInBufOverflow: + BPLOG(INFO) << "ExtabEntryExtract: .exidx/.extab section overrun"; + break; + case ExOutBufOverflow: + BPLOG(INFO) << "ExtabEntryExtract: bytecode buffer overflow"; + break; + case ExCantUnwind: + BPLOG(INFO) << "ExtabEntryExtract: function is marked CANT_UNWIND"; + break; + case ExCantRepresent: + BPLOG(INFO) << "ExtabEntryExtract: bytecode can't be represented"; + break; + case ExInvalid: + BPLOG(INFO) << "ExtabEntryExtract: index table entry is invalid"; + break; + default: + BPLOG(INFO) << "ExtabEntryExtract: unknown error: " << (int)res; + break; + } + continue; + } + + // Finally, work through the unwind instructions in |buf| and + // create CFI entries that Breakpad can use. This can also fail. + // First, add a new stack frame entry, into which ExtabEntryDecode + // will write the CFI entries. + handler_->AddStackFrame(addr, next_addr - addr); + int ret = ExtabEntryDecode(buf, buf_used); + if (ret < 0) { + handler_->DeleteStackFrame(); + BPLOG(INFO) << "ExtabEntryDecode: failed with error code: " << ret; + continue; + } + handler_->SubmitStackFrame(); + + } /* iterating over .exidx */ +} + +} // arm_ex_reader diff --git a/toolkit/crashreporter/google-breakpad/src/common/arm_ex_reader.h b/toolkit/crashreporter/google-breakpad/src/common/arm_ex_reader.h new file mode 100644 index 000000000000..450438e60137 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/arm_ex_reader.h @@ -0,0 +1,115 @@ + +/* libunwind - a platform-independent unwind library + Copyright 2011 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Derived from libunwind, with extensive modifications. + +#ifndef COMMON_ARM_EX_READER_H__ +#define COMMON_ARM_EX_READER_H__ + +#include "common/arm_ex_to_module.h" +#include "common/memory_range.h" + +namespace arm_ex_reader { + +// This class is a reader for ARM unwind information +// from .ARM.exidx and .ARM.extab sections. +class ExceptionTableInfo { + public: + ExceptionTableInfo(const char* exidx, size_t exidx_size, + const char* extab, size_t extab_size, + uint32_t text_last_svma, + arm_ex_to_module::ARMExToModule* handler, + const char* mapping_addr, + uint32_t loading_addr) + : mr_exidx_(google_breakpad::MemoryRange(exidx, exidx_size)), + mr_extab_(google_breakpad::MemoryRange(extab, extab_size)), + text_last_svma_(text_last_svma), + handler_(handler), mapping_addr_(mapping_addr), + loading_addr_(loading_addr) { } + + ~ExceptionTableInfo() { } + + // Parses the entries in .ARM.exidx and possibly + // in .ARM.extab tables, reports what we find to + // arm_ex_to_module::ARMExToModule. + void Start(); + + private: + google_breakpad::MemoryRange mr_exidx_; + google_breakpad::MemoryRange mr_extab_; + uint32_t text_last_svma_; + arm_ex_to_module::ARMExToModule* handler_; + const char* mapping_addr_; + uint32_t loading_addr_; + + enum ExExtractResult { + ExSuccess, // success + ExInBufOverflow, // out-of-range while reading .exidx + ExOutBufOverflow, // output buffer is too small + ExCantUnwind, // this function is marked CANT_UNWIND + ExCantRepresent, // entry valid, but we can't represent it + ExInvalid // entry is invalid + }; + ExExtractResult + ExtabEntryExtract(const struct arm_ex_to_module::exidx_entry* entry, + uint8_t* buf, size_t buf_size, + /*OUT*/size_t* buf_used); + + int ExtabEntryDecode(const uint8_t* buf, size_t buf_size); +}; + +} // namespace arm_ex_reader + +#endif // COMMON_ARM_EX_READER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/arm_ex_to_module.cc b/toolkit/crashreporter/google-breakpad/src/common/arm_ex_to_module.cc new file mode 100644 index 000000000000..27bc51be27ff --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/arm_ex_to_module.cc @@ -0,0 +1,206 @@ + +/* libunwind - a platform-independent unwind library + Copyright 2011 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Derived from libunwind, with extensive modifications. + +#include "common/unique_string.h" +#include "common/arm_ex_to_module.h" + +#include +#include + +// For big-picture comments on how the EXIDX reader works, +// see arm_ex_reader.cc. + +#define ARM_EXBUF_START(x) (((x) >> 4) & 0x0f) +#define ARM_EXBUF_COUNT(x) ((x) & 0x0f) +#define ARM_EXBUF_END(x) (ARM_EXBUF_START(x) + ARM_EXBUF_COUNT(x)) + +using google_breakpad::ustr__pc; +using google_breakpad::ustr__lr; +using google_breakpad::ustr__sp; +using google_breakpad::Module; +using google_breakpad::ToUniqueString; +using google_breakpad::UniqueString; + +namespace arm_ex_to_module { + +// Translate command from extab_data to command for Module. +int ARMExToModule::TranslateCmd(const struct extab_data* edata, + Module::StackFrameEntry* entry, string& vsp) { + int ret = 0; + switch (edata->cmd) { + case ARM_EXIDX_CMD_FINISH: + /* Copy LR to PC if there isn't currently a rule for PC in force. */ + if (entry->initial_rules.find(ustr__pc()) + == entry->initial_rules.end()) { + if (entry->initial_rules.find(ustr__lr()) + == entry->initial_rules.end()) { + entry->initial_rules[ustr__pc()] = Module::Expr("lr"); + } else { + entry->initial_rules[ustr__pc()] = entry->initial_rules[ustr__lr()]; + } + } + break; + case ARM_EXIDX_CMD_SUB_FROM_VSP: + { + char c[16]; + sprintf(c, " %d -", edata->data); + vsp += c; + } + break; + case ARM_EXIDX_CMD_ADD_TO_VSP: + { + char c[16]; + sprintf(c, " %d +", edata->data); + vsp += c; + } + break; + case ARM_EXIDX_CMD_REG_POP: + for (unsigned int i = 0; i < 16; i++) { + if (edata->data & (1 << i)) { + entry->initial_rules[ToUniqueString(regnames[i])] + = Module::Expr(vsp + " ^"); + vsp += " 4 +"; + } + } + /* Set cfa in case the SP got popped. */ + if (edata->data & (1 << 13)) { + Module::Expr& vsp_expr = entry->initial_rules[ustr__sp()]; + // It must be a postfix expression (we don't generate anything + // else here), so return -1 to fail out if it isn't. + if (!vsp_expr.isExprPostfix()) { + ret = -1; + break; + }; + vsp = vsp_expr.getExprPostfix(); + } + break; + case ARM_EXIDX_CMD_REG_TO_SP: { + assert (edata->data < 16); + const char* const regname = regnames[edata->data]; + const UniqueString* regname_us = ToUniqueString(regname); + if (entry->initial_rules.find(regname_us) == entry->initial_rules.end()) { + entry->initial_rules[ustr__sp()] = Module::Expr(regname); + } else { + entry->initial_rules[ustr__sp()] = entry->initial_rules[regname_us]; + } + Module::Expr& vsp_expr = entry->initial_rules[ustr__sp()]; + if (!vsp_expr.isExprPostfix()) { + ret = -1; + break; + }; + vsp = vsp_expr.getExprPostfix(); + break; + } + case ARM_EXIDX_CMD_VFP_POP: + /* Don't recover VFP registers, but be sure to adjust the stack + pointer. */ + for (unsigned int i = ARM_EXBUF_START(edata->data); + i <= ARM_EXBUF_END(edata->data); i++) { + vsp += " 8 +"; + } + if (!(edata->data & ARM_EXIDX_VFP_FSTMD)) { + vsp += " 4 +"; + } + break; + case ARM_EXIDX_CMD_WREG_POP: + for (unsigned int i = ARM_EXBUF_START(edata->data); + i <= ARM_EXBUF_END(edata->data); i++) { + vsp += " 8 +"; + } + break; + case ARM_EXIDX_CMD_WCGR_POP: + // Pop wCGR registers under mask {wCGR3,2,1,0}, hence "i < 4" + for (unsigned int i = 0; i < 4; i++) { + if (edata->data & (1 << i)) { + vsp += " 4 +"; + } + } + break; + case ARM_EXIDX_CMD_REFUSED: + case ARM_EXIDX_CMD_RESERVED: + ret = -1; + break; + } + return ret; +} + +void ARMExToModule::AddStackFrame(uintptr_t addr, size_t size) { + stack_frame_entry_ = new Module::StackFrameEntry; + stack_frame_entry_->address = addr; + stack_frame_entry_->size = size; + stack_frame_entry_->initial_rules[ToUniqueString(kCFA)] = Module::Expr("sp"); + vsp_ = "sp"; +} + +int ARMExToModule::ImproveStackFrame(const struct extab_data* edata) { + return TranslateCmd(edata, stack_frame_entry_, vsp_) ; +} + +void ARMExToModule::DeleteStackFrame() { + delete stack_frame_entry_; +} + +void ARMExToModule::SubmitStackFrame() { + // return address always winds up in pc + stack_frame_entry_->initial_rules[ToUniqueString(kRA)] + = stack_frame_entry_->initial_rules[ustr__pc()]; + // the final value of vsp is the new value of sp + stack_frame_entry_->initial_rules[ustr__sp()] = vsp_; + module_->AddStackFrameEntry(stack_frame_entry_); +} + +} // namespace arm_ex_to_module diff --git a/toolkit/crashreporter/google-breakpad/src/common/arm_ex_to_module.h b/toolkit/crashreporter/google-breakpad/src/common/arm_ex_to_module.h new file mode 100644 index 000000000000..d35c693226e6 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/arm_ex_to_module.h @@ -0,0 +1,129 @@ + +/* libunwind - a platform-independent unwind library + Copyright 2011 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Derived from libunwind, with extensive modifications. + +#ifndef COMMON_ARM_EX_TO_MODULE__ +#define COMMON_ARM_EX_TO_MODULE__ + +#include "common/module.h" + +#include + +namespace arm_ex_to_module { + +using google_breakpad::Module; + +typedef enum extab_cmd { + ARM_EXIDX_CMD_FINISH, + ARM_EXIDX_CMD_SUB_FROM_VSP, + ARM_EXIDX_CMD_ADD_TO_VSP, + ARM_EXIDX_CMD_REG_POP, + ARM_EXIDX_CMD_REG_TO_SP, + ARM_EXIDX_CMD_VFP_POP, + ARM_EXIDX_CMD_WREG_POP, + ARM_EXIDX_CMD_WCGR_POP, + ARM_EXIDX_CMD_RESERVED, + ARM_EXIDX_CMD_REFUSED, +} extab_cmd_t; + +struct exidx_entry { + uint32_t addr; + uint32_t data; +}; + +struct extab_data { + extab_cmd_t cmd; + uint32_t data; +}; + +enum extab_cmd_flags { + ARM_EXIDX_VFP_SHIFT_16 = 1 << 16, + ARM_EXIDX_VFP_FSTMD = 1 << 17, // distinguishes FSTMxxD from FSTMxxX +}; + +const string kRA = ".ra"; +const string kCFA = ".cfa"; + +static const char* const regnames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "fps", "cpsr" +}; + +// Receives information from arm_ex_reader::ExceptionTableInfo +// and adds it to the Module object +class ARMExToModule { + public: + ARMExToModule(Module* module) + : module_(module) { } + ~ARMExToModule() { } + void AddStackFrame(uintptr_t addr, size_t size); + int ImproveStackFrame(const struct extab_data* edata); + void DeleteStackFrame(); + void SubmitStackFrame(); + private: + Module* module_; + Module::StackFrameEntry* stack_frame_entry_; + string vsp_; + int TranslateCmd(const struct extab_data* edata, + Module::StackFrameEntry* entry, + string& vsp); +}; + +} // namespace arm_ex_to_module + +#endif // COMMON_ARM_EX_TO_MODULE__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.cc index 172860eb4f35..6eebf3dcd697 100644 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.cc +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.cc @@ -52,6 +52,7 @@ #include #include +#include "common/arm_ex_reader.h" #include "common/dwarf/bytereader-inl.h" #include "common/dwarf/dwarf2diehandler.h" #include "common/dwarf_cfi_to_module.h" @@ -70,6 +71,10 @@ #include "common/using_std_string.h" #include "common/logging.h" +#if defined(__ANDROID__) && !defined(SHT_ARM_EXIDX) +# define SHT_ARM_EXIDX (SHT_LOPROC + 1) +#endif + // This namespace contains helper functions. namespace { @@ -345,6 +350,52 @@ bool LoadDwarfCFI(const string& dwarf_filename, return true; } +template +bool LoadARMexidx(const typename ElfClass::Ehdr* elf_header, + const typename ElfClass::Shdr* exidx_section, + const typename ElfClass::Shdr* extab_section, + uint32_t loading_addr, + Module* module) { + // To do this properly we need to know: + // * the bounds of the .ARM.exidx section in the mapped image + // * the bounds of the .ARM.extab section in the mapped image + // * the vma of the last byte in the text section associated with the .exidx + // The first two are easy. The third is a bit tricky. If we can't + // figure out what it is, just pass in zero. + const char *exidx_img + = GetOffset(elf_header, exidx_section->sh_offset); + size_t exidx_size = exidx_section->sh_size; + const char *extab_img + = GetOffset(elf_header, extab_section->sh_offset); + size_t extab_size = extab_section->sh_size; + + // The sh_link field of the exidx section gives the section number + // for the associated text section. + uint32_t exidx_text_last_svma = 0; + int exidx_text_sno = exidx_section->sh_link; + typedef typename ElfClass::Shdr Shdr; + // |sections| points to the section header table + const Shdr* sections + = GetOffset(elf_header, elf_header->e_shoff); + const int num_sections = elf_header->e_shnum; + if (exidx_text_sno >= 0 && exidx_text_sno < num_sections) { + const Shdr* exidx_text_shdr = §ions[exidx_text_sno]; + if (exidx_text_shdr->sh_size > 0) { + exidx_text_last_svma + = exidx_text_shdr->sh_addr + exidx_text_shdr->sh_size - 1; + } + } + + arm_ex_to_module::ARMExToModule handler(module); + arm_ex_reader::ExceptionTableInfo + parser(exidx_img, exidx_size, extab_img, extab_size, exidx_text_last_svma, + &handler, + reinterpret_cast(elf_header), + loading_addr); + parser.Start(); + return true; +} + bool LoadELF(const string& obj_file, MmapWrapper* map_wrapper, void** elf_header) { int obj_fd = open(obj_file.c_str(), O_RDONLY); @@ -634,6 +685,29 @@ bool LoadSymbols(const string& obj_file, } } + // ARM has special unwind tables that can be used. + const Shdr* arm_exidx_section = + FindElfSectionByName(".ARM.exidx", SHT_ARM_EXIDX, + sections, names, names_end, + elf_header->e_shnum); + const Shdr* arm_extab_section = + FindElfSectionByName(".ARM.extab", SHT_PROGBITS, + sections, names, names_end, + elf_header->e_shnum); + // Only load information from this section if there isn't a .debug_info + // section. + if (!found_debug_info_section + && arm_exidx_section && arm_extab_section && symbol_data != NO_CFI) { + info->LoadedSection(".ARM.exidx"); + info->LoadedSection(".ARM.extab"); + bool result = LoadARMexidx(elf_header, + arm_exidx_section, arm_extab_section, + loading_addr, module); + found_usable_info = found_usable_info || result; + if (result) + BPLOG(INFO) << "LoadSymbols: read EXIDX from .ARM.{exidx,extab}"; + } + if (!found_debug_info_section && symbol_data != ONLY_CFI) { fprintf(stderr, "%s: file contains no debugging information" " (no \".stab\" or \".debug_info\" sections)\n", diff --git a/toolkit/crashreporter/google-breakpad/src/common/module.cc b/toolkit/crashreporter/google-breakpad/src/common/module.cc index 1edacbced506..5b3d334ec397 100644 --- a/toolkit/crashreporter/google-breakpad/src/common/module.cc +++ b/toolkit/crashreporter/google-breakpad/src/common/module.cc @@ -258,7 +258,7 @@ bool Module::ReportError() { } std::ostream& operator<<(std::ostream& stream, const Module::Expr& expr) { - assert(!expr.invalid()); + assert(!expr.isExprInvalid()); switch (expr.how_) { case Module::kExprSimple: stream << expr.ident_ << " " << expr.offset_ << " +"; diff --git a/toolkit/crashreporter/google-breakpad/src/common/module.h b/toolkit/crashreporter/google-breakpad/src/common/module.h index f67274749e6a..ef894f83397c 100644 --- a/toolkit/crashreporter/google-breakpad/src/common/module.h +++ b/toolkit/crashreporter/google-breakpad/src/common/module.h @@ -165,7 +165,14 @@ class Module { offset_ = 0; how_ = kExprInvalid; } - bool invalid() const { return how_ == kExprInvalid; } + bool isExprInvalid() const { return how_ == kExprInvalid; } + bool isExprPostfix() const { return how_ == kExprPostfix; } + + // Return the postfix expression string. This is only + // meaningful on Exprs for which isExprPostfix returns true. + // In all other cases it returns an empty string. + string getExprPostfix() const { return postfix_; } + bool operator==(const Expr& other) const { return how_ == other.how_ && ident_ == other.ident_ && diff --git a/toolkit/crashreporter/google-breakpad/src/common/moz.build b/toolkit/crashreporter/google-breakpad/src/common/moz.build index 7412aae93c2c..9c146f81aefd 100644 --- a/toolkit/crashreporter/google-breakpad/src/common/moz.build +++ b/toolkit/crashreporter/google-breakpad/src/common/moz.build @@ -31,6 +31,8 @@ if CONFIG['OS_TARGET'] != 'WINNT': 'language.cc', 'dwarf/dwarf2diehandler.cc', 'dwarf_line_to_module.cc', + 'arm_ex_reader.cc', + 'arm_ex_to_module.cc', ] if CONFIG['OS_ARCH'] == 'Linux': diff --git a/toolkit/crashreporter/google-breakpad/src/common/unique_string.h b/toolkit/crashreporter/google-breakpad/src/common/unique_string.h index e551a750ae18..9db3d7519621 100644 --- a/toolkit/crashreporter/google-breakpad/src/common/unique_string.h +++ b/toolkit/crashreporter/google-breakpad/src/common/unique_string.h @@ -235,6 +235,27 @@ inline static const UniqueString* ustr__ZDra() { return us; } +// "pc" +inline static const UniqueString* ustr__pc() { + static const UniqueString* us = NULL; + if (!us) us = ToUniqueString("pc"); + return us; +} + +// "lr" +inline static const UniqueString* ustr__lr() { + static const UniqueString* us = NULL; + if (!us) us = ToUniqueString("lr"); + return us; +} + +// "sp" +inline static const UniqueString* ustr__sp() { + static const UniqueString* us = NULL; + if (!us) us = ToUniqueString("sp"); + return us; +} + template class UniqueStringMap { diff --git a/toolkit/crashreporter/google-breakpad/src/processor/cfi_frame_info.cc b/toolkit/crashreporter/google-breakpad/src/processor/cfi_frame_info.cc index a043f9c19e25..ebaf4533e827 100644 --- a/toolkit/crashreporter/google-breakpad/src/processor/cfi_frame_info.cc +++ b/toolkit/crashreporter/google-breakpad/src/processor/cfi_frame_info.cc @@ -54,7 +54,7 @@ bool CFIFrameInfo::FindCallerRegs(const RegisterValueMap ®isters, RegisterValueMap *caller_registers) const { // If there are not rules for both .ra and .cfa in effect at this address, // don't use this CFI data for stack walking. - if (cfa_rule_.invalid() || ra_rule_.invalid()) + if (cfa_rule_.isExprInvalid() || ra_rule_.isExprInvalid()) return false; RegisterValueMap working; @@ -105,10 +105,10 @@ template bool CFIFrameInfo::FindCallerRegs( string CFIFrameInfo::Serialize() const { std::ostringstream stream; - if (!cfa_rule_.invalid()) { + if (!cfa_rule_.isExprInvalid()) { stream << ".cfa: " << cfa_rule_; } - if (!ra_rule_.invalid()) { + if (!ra_rule_.isExprInvalid()) { if (static_cast(stream.tellp()) != 0) stream << " "; stream << ".ra: " << ra_rule_; From 422cdcd4f2cd0ff70ac0ad611bc67e6771be8e8d Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Thu, 25 Apr 2013 13:56:43 -0400 Subject: [PATCH 06/84] Bug 844852 - Run GTest on make check. r=ted --HG-- extra : rebase_source : dabb338ee02acf390dabf1cda8ed6d89f8857fdf --- gfx/tests/gtest/TestTiledLayerBuffer.cpp | 1 - testing/gtest/Makefile.in | 1 + testing/gtest/mozilla/GTestRunner.cpp | 29 +++++ testing/gtest/rungtests.py | 129 +++++++++++++++++++++++ 4 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 testing/gtest/rungtests.py diff --git a/gfx/tests/gtest/TestTiledLayerBuffer.cpp b/gfx/tests/gtest/TestTiledLayerBuffer.cpp index 2909fd7d3724..339558c7dddc 100644 --- a/gfx/tests/gtest/TestTiledLayerBuffer.cpp +++ b/gfx/tests/gtest/TestTiledLayerBuffer.cpp @@ -68,7 +68,6 @@ TEST(TiledLayerBuffer, TileStart) { TEST(TiledLayerBuffer, EmptyUpdate) { TestTiledLayerBuffer buffer; - nsRegion::InitStatic(); nsIntRegion validRegion(nsIntRect(0, 0, 10, 10)); buffer.TestUpdate(validRegion, validRegion); diff --git a/testing/gtest/Makefile.in b/testing/gtest/Makefile.in index e332f819606f..f6c6d5e5da8c 100644 --- a/testing/gtest/Makefile.in +++ b/testing/gtest/Makefile.in @@ -45,6 +45,7 @@ check gtest:: ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) $(MAKE) -C $(DEPTH)/browser/app repackage endif + $(PYTHON) $(topsrcdir)/testing/gtest/rungtests.py --xre-path=$(DIST)/bin --symbols-path=$(DIST)/crashreporter-symbols $(DIST)/bin/$(MOZ_APP_NAME)$(BIN_SUFFIX) endif endif diff --git a/testing/gtest/mozilla/GTestRunner.cpp b/testing/gtest/mozilla/GTestRunner.cpp index 863c4242058d..6fd15d6d1be1 100644 --- a/testing/gtest/mozilla/GTestRunner.cpp +++ b/testing/gtest/mozilla/GTestRunner.cpp @@ -7,6 +7,10 @@ #include "gtest/gtest.h" #include "mozilla/Attributes.h" #include "mozilla/NullPtr.h" +#ifdef MOZ_CRASHREPORTER +#include "nsICrashReporter.h" +#endif +#include "testing/TestHarness.h" #include "prenv.h" using ::testing::EmptyTestEventListener; @@ -78,6 +82,31 @@ int RunGTestFunc() PR_SetEnv("XPCOM_DEBUG_BREAK=stack-and-abort"); + ScopedXPCOM xpcom("AsyncPanZoomController"); + +#ifdef MOZ_CRASHREPORTER + nsCOMPtr crashreporter; + char *crashreporterStr = PR_GetEnv("MOZ_CRASHREPORTER"); + if (crashreporterStr && !strcmp(crashreporterStr, "1")) { + //TODO: move this to an even-more-common location to use in all + // C++ unittests + crashreporter = do_GetService("@mozilla.org/toolkit/crash-reporter;1"); + if (crashreporter) { + std::cerr << "Setting up crash reporting" << std::endl; + + nsCOMPtr dirsvc = + do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID); + nsCOMPtr cwd; + nsresult rv = dirsvc->Get(NS_OS_CURRENT_WORKING_DIR, + NS_GET_IID(nsIFile), + getter_AddRefs(cwd)); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + crashreporter->SetEnabled(true); + crashreporter->SetMinidumpPath(cwd); + } + } +#endif + return RUN_ALL_TESTS(); } diff --git a/testing/gtest/rungtests.py b/testing/gtest/rungtests.py new file mode 100644 index 000000000000..803a87be90c0 --- /dev/null +++ b/testing/gtest/rungtests.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +from __future__ import with_statement +import sys, os, tempfile, shutil +from optparse import OptionParser +import mozprocess, mozinfo, mozlog, mozcrash +from contextlib import contextmanager + +log = mozlog.getLogger('gtests') + +class GTests(object): + # Time (seconds) to wait for test process to complete + TEST_PROC_TIMEOUT = 1200 + # Time (seconds) in which process will be killed if it produces no output. + TEST_PROC_NO_OUTPUT_TIMEOUT = 300 + + def run_gtest(self, prog, xre_path, symbols_path=None): + """ + Run a single C++ unit test program. + + Arguments: + * prog: The path to the test program to run. + * env: The environment to use for running the program. + * symbols_path: A path to a directory containing Breakpad-formatted + symbol files for producing stack traces on crash. + + Return True if the program exits with a zero status, False otherwise. + """ + self.xre_path = xre_path + env = self.build_environment() + basename = os.path.basename(prog) + log.info("Running test %s", basename) + proc = mozprocess.ProcessHandler([prog, "-unittest"], + cwd=os.getcwd(), + env=env) + #TODO: After bug 811320 is fixed, don't let .run() kill the process, + # instead use a timeout in .wait() and then kill to get a stack. + proc.run(timeout=GTests.TEST_PROC_TIMEOUT, + outputTimeout=GTests.TEST_PROC_NO_OUTPUT_TIMEOUT) + proc.wait() + if proc.timedOut: + log.testFail("%s | timed out after %d seconds", + basename, GTests.TEST_PROC_TIMEOUT) + return False + if mozcrash.check_for_crashes(os.getcwd(), symbols_path, + test_name=basename): + log.testFail("%s | test crashed", basename) + return False + result = proc.proc.returncode == 0 + if not result: + log.testFail("%s | test failed with return code %d", + basename, proc.proc.returncode) + return result + + def build_core_environment(self, env = {}): + """ + Add environment variables likely to be used across all platforms, including remote systems. + """ + env["MOZILLA_FIVE_HOME"] = self.xre_path + env["MOZ_XRE_DIR"] = self.xre_path + env["XPCOM_DEBUG_BREAK"] = "stack-and-abort" + env["MOZ_CRASHREPORTER_NO_REPORT"] = "1" + env["MOZ_CRASHREPORTER"] = "1" + env["MOZ_RUN_GTEST"] = "1" + # Normally we run with GTest default output, override this to use the TBPL test format. + env["MOZ_TBPL_PARSER"] = "1" + return env + + def build_environment(self): + """ + Create and return a dictionary of all the appropriate env variables and values. + On a remote system, we overload this to set different values and are missing things like os.environ and PATH. + """ + if not os.path.isdir(self.xre_path): + raise Exception("xre_path does not exist: %s", self.xre_path) + env = dict(os.environ) + env = self.build_core_environment(env) + pathvar = "" + if mozinfo.os == "linux": + pathvar = "LD_LIBRARY_PATH" + elif mozinfo.os == "mac": + pathvar = "DYLD_LIBRARY_PATH" + elif mozinfo.os == "win": + pathvar = "PATH" + if pathvar: + if pathvar in env: + env[pathvar] = "%s%s%s" % (self.xre_path, os.pathsep, env[pathvar]) + else: + env[pathvar] = self.xre_path + return env + +class gtestOptions(OptionParser): + def __init__(self): + OptionParser.__init__(self) + self.add_option("--xre-path", + action = "store", type = "string", dest = "xre_path", + default = None, + help = "absolute path to directory containing XRE (probably xulrunner)") + self.add_option("--symbols-path", + action = "store", type = "string", dest = "symbols_path", + default = None, + help = "absolute path to directory containing breakpad symbols, or the URL of a zip file containing symbols") + +def main(): + parser = gtestOptions() + options, args = parser.parse_args() + if not args: + print >>sys.stderr, """Usage: %s """ % sys.argv[0] + sys.exit(1) + if not options.xre_path: + print >>sys.stderr, """Error: --xre-path is required""" + sys.exit(1) + prog = os.path.abspath(args[0]) + options.xre_path = os.path.abspath(options.xre_path) + tester = GTests() + try: + result = tester.run_gtest(prog, options.xre_path, options.symbols_path) + except Exception, e: + log.error(str(e)) + result = False + sys.exit(0 if result else 1) + +if __name__ == '__main__': + main() + From 3df775367ad7687c87f757f02c0f76ae79a2f638 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Fri, 14 Jun 2013 09:46:28 +0200 Subject: [PATCH 07/84] Bug 882111 part 1 - Some js::Interpret cleanup. r=luke --- js/src/vm/Interpreter.cpp | 76 +++++++++++++++------------------------ js/src/vm/Interpreter.h | 25 ------------- 2 files changed, 28 insertions(+), 73 deletions(-) diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index a9a224f43dec..f251b8106916 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -280,6 +280,9 @@ js::ValueToCallable(JSContext *cx, const Value &v, int numToSkip, MaybeConstruct return NULL; } +static JS_NEVER_INLINE bool +Interpret(JSContext *cx, StackFrame *entryFrame); + bool js::RunScript(JSContext *cx, StackFrame *fp) { @@ -342,7 +345,7 @@ js::RunScript(JSContext *cx, StackFrame *fp) } #endif - return Interpret(cx, fp) != Interpret_Error; + return Interpret(cx, fp); } /* @@ -985,13 +988,12 @@ js::IteratorNext(JSContext *cx, HandleObject iterobj, MutableHandleValue rval) return js_IteratorNext(cx, iterobj, rval); } -JS_NEVER_INLINE InterpretStatus -js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode, bool useNewType) +static JS_NEVER_INLINE bool +Interpret(JSContext *cx, StackFrame *entryFrame) { JSAutoResolveFlags rf(cx, RESOLVE_INFER); - if (interpMode == JSINTERP_NORMAL) - gc::MaybeVerifyBarriers(cx, true); + gc::MaybeVerifyBarriers(cx, true); JS_ASSERT(!cx->compartment()->activeAnalysis); @@ -1060,8 +1062,6 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode, bool script = (s); \ if (script->hasAnyBreakpointsOrStepMode() || script->hasScriptCounts) \ interrupts.enable(); \ - JS_ASSERT_IF(interpMode == JSINTERP_SKIP_TRAP, \ - script->hasAnyBreakpointsOrStepMode()); \ JS_END_MACRO /* Repoint cx->regs to a local variable for faster access. */ @@ -1128,43 +1128,28 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode, bool /* State communicated between non-local jumps: */ bool interpReturnOK; - /* Don't call the script prologue if executing between Method and Trace JIT. */ - if (interpMode == JSINTERP_NORMAL) { - StackFrame *fp = regs.fp(); - if (!fp->isGeneratorFrame()) { - if (!fp->prologue(cx)) - goto error; - } else { - Probes::enterScript(cx, script, script->function(), fp); - } - if (cx->compartment()->debugMode()) { - JSTrapStatus status = ScriptDebugPrologue(cx, fp); - switch (status) { - case JSTRAP_CONTINUE: - break; - case JSTRAP_RETURN: - interpReturnOK = true; - goto forced_return; - case JSTRAP_THROW: - case JSTRAP_ERROR: - goto error; - default: - JS_NOT_REACHED("bad ScriptDebugPrologue status"); - } + if (!entryFrame->isGeneratorFrame()) { + if (!entryFrame->prologue(cx)) + goto error; + } else { + Probes::enterScript(cx, script, script->function(), entryFrame); + } + if (cx->compartment()->debugMode()) { + JSTrapStatus status = ScriptDebugPrologue(cx, entryFrame); + switch (status) { + case JSTRAP_CONTINUE: + break; + case JSTRAP_RETURN: + interpReturnOK = true; + goto forced_return; + case JSTRAP_THROW: + case JSTRAP_ERROR: + goto error; + default: + JS_NOT_REACHED("bad ScriptDebugPrologue status"); } } - /* The REJOIN mode acts like the normal mode, except the prologue is skipped. */ - if (interpMode == JSINTERP_REJOIN) - interpMode = JSINTERP_NORMAL; - - /* - * The RETHROW mode acts like a bailout mode, except that it resume an - * exception instead of resuming the script. - */ - if (interpMode == JSINTERP_RETHROW) - goto error; - /* * It is important that "op" be initialized before calling DO_OP because * it is possible for "op" to be specially assigned during the normal @@ -1240,7 +1225,7 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode, bool if (script->hasAnyBreakpointsOrStepMode()) moreInterrupts = true; - if (script->hasBreakpointsAt(regs.pc) && interpMode != JSINTERP_SKIP_TRAP) { + if (script->hasBreakpointsAt(regs.pc)) { RootedValue rval(cx); JSTrapStatus status = Debugger::onTrap(cx, &rval); switch (status) { @@ -1260,8 +1245,6 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode, bool JS_ASSERT(rval.isInt32() && rval.toInt32() == op); } - interpMode = JSINTERP_NORMAL; - switchMask = moreInterrupts ? -1 : 0; switchOp = int(op); goto do_switch; @@ -3022,9 +3005,6 @@ END_CASE(JSOP_ARRAYPUSH) JS_ASSERT(&cx->regs() == ®s); JS_ASSERT(uint32_t(regs.pc - script->code) < script->length); - /* When rejoining, we must not err before finishing Interpret's prologue. */ - JS_ASSERT(interpMode != JSINTERP_REJOIN); - if (cx->isExceptionPending()) { /* Call debugger throw hooks. */ if (cx->compartment()->debugMode()) { @@ -3149,7 +3129,7 @@ END_CASE(JSOP_ARRAYPUSH) leave_on_safe_point: #endif - return interpReturnOK ? Interpret_Ok : Interpret_Error; + return interpReturnOK; } bool diff --git a/js/src/vm/Interpreter.h b/js/src/vm/Interpreter.h index 61605bb508dd..f46b63d048ac 100644 --- a/js/src/vm/Interpreter.h +++ b/js/src/vm/Interpreter.h @@ -164,31 +164,6 @@ ExecuteKernel(JSContext *cx, HandleScript script, JSObject &scopeChain, const Va extern bool Execute(JSContext *cx, HandleScript script, JSObject &scopeChain, Value *rval); -/* Flags to toggle js::Interpret() execution. */ -enum InterpMode -{ - JSINTERP_NORMAL = 0, /* interpreter is running normally */ - JSINTERP_REJOIN = 1, /* as normal, but the frame has already started */ - JSINTERP_SKIP_TRAP = 2, /* as REJOIN, but skip trap at first opcode */ - JSINTERP_BAILOUT = 3, /* interpreter is running from an Ion bailout */ - JSINTERP_RETHROW = 4 /* as BAILOUT, but unwind all frames */ -}; - -enum InterpretStatus -{ - Interpret_Error = 0, /* interpreter had an error */ - Interpret_Ok = 1, /* interpreter executed successfully */ - Interpret_OSR = 2 /* when mode=BAILOUT and we should OSR into Ion */ -}; - -/* - * Execute the caller-initialized frame for a user-defined script or function - * pointed to by cx->fp until completion or error. - */ -extern JS_NEVER_INLINE InterpretStatus -Interpret(JSContext *cx, StackFrame *stopFp, InterpMode mode = JSINTERP_NORMAL, - bool useNewType = false); - extern bool RunScript(JSContext *cx, StackFrame *fp); From 85d4cce0e51c878ad901e088b9fbdf0447e3b251 Mon Sep 17 00:00:00 2001 From: "Nicholas D. Matsakis" Date: Thu, 6 Jun 2013 11:01:15 -0400 Subject: [PATCH 08/84] Bug 880208 - Add UnsafeGet and UnsafeGetImmutable intrinsics r=djvj --- js/src/builtin/ParallelArray.js | 37 +++++++++--------- js/src/ion/IonBuilder.cpp | 34 +++++++++++------ js/src/ion/IonBuilder.h | 18 ++++++++- js/src/ion/MCallOptimize.cpp | 31 +++++++++++++++- js/src/ion/MIR.h | 15 ++++++-- js/src/jscntxt.h | 3 ++ js/src/vm/SelfHosting.cpp | 66 +++++++++++++++++++++++++++++---- 7 files changed, 163 insertions(+), 41 deletions(-) diff --git a/js/src/builtin/ParallelArray.js b/js/src/builtin/ParallelArray.js index 98213378053a..0a2db707446f 100644 --- a/js/src/builtin/ParallelArray.js +++ b/js/src/builtin/ParallelArray.js @@ -377,7 +377,7 @@ function ParallelArrayMap(func, mode) { // FIXME(bug 844887): Check |IsCallable(func)| var self = this; - var length = self.shape[0]; + var length = UnsafeGetImmutableElement(self.shape, 0); var buffer = NewDenseArray(length); parallel: for (;;) { // see ParallelArrayBuild() to explain why for(;;) etc @@ -432,7 +432,7 @@ function ParallelArrayReduce(func, mode) { // FIXME(bug 844887): Check |IsCallable(func)| var self = this; - var length = self.shape[0]; + var length = UnsafeGetImmutableElement(self.shape, 0); if (length === 0) ThrowError(JSMSG_PAR_ARRAY_REDUCE_EMPTY); @@ -519,7 +519,7 @@ function ParallelArrayScan(func, mode) { // FIXME(bug 844887): Check |IsCallable(func)| var self = this; - var length = self.shape[0]; + var length = UnsafeGetImmutableElement(self.shape, 0); if (length === 0) ThrowError(JSMSG_PAR_ARRAY_REDUCE_EMPTY); @@ -726,7 +726,7 @@ function ParallelArrayScatter(targets, defaultValue, conflictFunc, length, mode) var self = this; if (length === undefined) - length = self.shape[0]; + length = UnsafeGetImmutableElement(self.shape, 0); // The Divide-Scatter-Vector strategy: // 1. Slice |targets| array of indices ("scatter-vector") into N @@ -977,7 +977,7 @@ function ParallelArrayFilter(func, mode) { // FIXME(bug 844887): Check |IsCallable(func)| var self = this; - var length = self.shape[0]; + var length = UnsafeGetImmutableElement(self.shape, 0); parallel: for (;;) { // see ParallelArrayBuild() to explain why for(;;) etc if (ShouldForceSequential()) @@ -1151,6 +1151,11 @@ function ParallelArrayFlatten() { function ParallelArrayGet1(i) { if (i === undefined) return undefined; + + // We could use UnsafeGetImmutableElement here, but I am not doing + // so (for the moment) since using the default path enables + // bounds-check hoisting, which is (currently) not possible + // otherwise. return this.buffer[this.offset + i]; } @@ -1158,27 +1163,25 @@ function ParallelArrayGet1(i) { * Specialized variant of get() for two-dimensional case */ function ParallelArrayGet2(x, y) { - var xDimension = this.shape[0]; - var yDimension = this.shape[1]; - if (x === undefined) - return undefined; - if (x >= xDimension) + var xDimension = UnsafeGetImmutableElement(this.shape, 0); + var yDimension = UnsafeGetImmutableElement(this.shape, 1); + if (x === undefined || TO_INT32(x) !== x || x >= xDimension) return undefined; if (y === undefined) return NewParallelArray(ParallelArrayView, [yDimension], this.buffer, this.offset + x * yDimension); - if (y >= yDimension) + if (TO_INT32(y) !== y || y >= yDimension) return undefined; var offset = y + x * yDimension; - return this.buffer[this.offset + offset]; + return UnsafeGetImmutableElement(this.buffer, this.offset + offset); } /** * Specialized variant of get() for three-dimensional case */ function ParallelArrayGet3(x, y, z) { - var xDimension = this.shape[0]; - var yDimension = this.shape[1]; - var zDimension = this.shape[2]; + var xDimension = UnsafeGetImmutableElement(this.shape, 0); + var yDimension = UnsafeGetImmutableElement(this.shape, 1); + var zDimension = UnsafeGetImmutableElement(this.shape, 2); if (x === undefined) return undefined; if (x >= xDimension) @@ -1194,7 +1197,7 @@ function ParallelArrayGet3(x, y, z) { if (z >= zDimension) return undefined; var offset = z + y*zDimension + x * yDimension * zDimension; - return this.buffer[this.offset + offset]; + return UnsafeGetImmutableElement(this.buffer, this.offset + offset); } /** @@ -1228,7 +1231,7 @@ function ParallelArrayGetN(...coords) { /** The length property yields the outermost dimension */ function ParallelArrayLength() { - return this.shape[0]; + return UnsafeGetImmutableElement(this.shape, 0); } function ParallelArrayToString() { diff --git a/js/src/ion/IonBuilder.cpp b/js/src/ion/IonBuilder.cpp index 4d8786b3b11a..4d35f622915a 100644 --- a/js/src/ion/IonBuilder.cpp +++ b/js/src/ion/IonBuilder.cpp @@ -6264,8 +6264,11 @@ IonBuilder::jsop_getelem() if (ElementAccessIsDenseNative(obj, index)) { // Don't generate a fast path if there have been bounds check failures // and this access might be on a sparse property. - if (!ElementAccessHasExtraIndexedProperty(cx, obj) || !failedBoundsCheck_) - return jsop_getelem_dense(); + if (!ElementAccessHasExtraIndexedProperty(cx, obj) || !failedBoundsCheck_) { + MDefinition *id = current->pop(); + MDefinition *obj = current->pop(); + return jsop_getelem_dense(GetElem_Normal, obj, id); + } } int arrayType = TypedArray::TYPE_MAX; @@ -6330,11 +6333,8 @@ IonBuilder::jsop_getelem() } bool -IonBuilder::jsop_getelem_dense() +IonBuilder::jsop_getelem_dense(GetElemSafety safety, MDefinition *obj, MDefinition *id) { - MDefinition *id = current->pop(); - MDefinition *obj = current->pop(); - types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc); if (JSOp(*pc) == JSOP_CALLELEM && !id->mightBeType(MIRType_String) && types->noConstraints()) { @@ -6351,6 +6351,7 @@ IonBuilder::jsop_getelem_dense() // undefined values have been observed at this access site and the access // cannot hit another indexed property on the object or its prototypes. bool readOutOfBounds = + safety == GetElem_Normal && types->hasType(types::Type::UndefinedType()) && !ElementAccessHasExtraIndexedProperty(cx, obj); @@ -6387,9 +6388,6 @@ IonBuilder::jsop_getelem_dense() if (loadDouble) elements = addConvertElementsToDoubles(elements); - MInitializedLength *initLength = MInitializedLength::New(elements); - current->add(initLength); - MInstruction *load; if (!readOutOfBounds) { @@ -6397,14 +6395,28 @@ IonBuilder::jsop_getelem_dense() // in-bounds elements, and the array is packed or its holes are not // read. This is the best case: we can separate the bounds check for // hoisting. - id = addBoundsCheck(id, initLength); + switch (safety) { + case GetElem_Normal: { + MInitializedLength *initLength = MInitializedLength::New(elements); + current->add(initLength); + id = addBoundsCheck(id, initLength); + break; + } - load = MLoadElement::New(elements, id, needsHoleCheck, loadDouble); + case GetElem_Unsafe: break; + case GetElem_UnsafeImmutable: break; + } + + bool knownImmutable = (safety == GetElem_UnsafeImmutable); + load = MLoadElement::New(elements, id, needsHoleCheck, loadDouble, + knownImmutable); current->add(load); } else { // This load may return undefined, so assume that we *can* read holes, // or that we can read out-of-bounds accesses. In this case, the bounds // check is part of the opcode. + MInitializedLength *initLength = MInitializedLength::New(elements); + current->add(initLength); load = MLoadElementHole::New(elements, id, initLength, needsHoleCheck); current->add(load); diff --git a/js/src/ion/IonBuilder.h b/js/src/ion/IonBuilder.h index e1a47e2c01da..d918f84eca56 100644 --- a/js/src/ion/IonBuilder.h +++ b/js/src/ion/IonBuilder.h @@ -41,6 +41,20 @@ class IonBuilder : public MIRGenerator SetElem_Unsafe, }; + enum GetElemSafety { + // Normal read like a[b] + GetElem_Normal, + + // Read due to UnsafeGetElement: + // - assumed to be in bounds, + GetElem_Unsafe, + + // Read due to UnsafeGetImmutableElement: + // - assumed to be in bounds, + // - assumed not to alias any stores + GetElem_UnsafeImmutable, + }; + struct DeferredEdge : public TempObject { MBasicBlock *block; @@ -391,7 +405,7 @@ class IonBuilder : public MIRGenerator bool jsop_intrinsic(HandlePropertyName name); bool jsop_bindname(PropertyName *name); bool jsop_getelem(); - bool jsop_getelem_dense(); + bool jsop_getelem_dense(GetElemSafety safety, MDefinition *object, MDefinition *index); bool jsop_getelem_typed(int arrayType); bool jsop_getelem_typed_static(bool *psucceeded); bool jsop_getelem_string(); @@ -486,6 +500,8 @@ class IonBuilder : public MIRGenerator InliningStatus inlineUnsafeSetElement(CallInfo &callInfo); bool inlineUnsafeSetDenseArrayElement(CallInfo &callInfo, uint32_t base); bool inlineUnsafeSetTypedArrayElement(CallInfo &callInfo, uint32_t base, int arrayType); + InliningStatus inlineUnsafeGetElement(CallInfo &callInfo, + GetElemSafety safety); InliningStatus inlineForceSequentialOrInParallelSection(CallInfo &callInfo); InliningStatus inlineNewDenseArray(CallInfo &callInfo); InliningStatus inlineNewDenseArrayForSequentialExecution(CallInfo &callInfo); diff --git a/js/src/ion/MCallOptimize.cpp b/js/src/ion/MCallOptimize.cpp index e2691532e577..06cb9a79297f 100644 --- a/js/src/ion/MCallOptimize.cpp +++ b/js/src/ion/MCallOptimize.cpp @@ -90,6 +90,10 @@ IonBuilder::inlineNativeCall(CallInfo &callInfo, JSNative native) // Array intrinsics. if (native == intrinsic_UnsafeSetElement) return inlineUnsafeSetElement(callInfo); + if (native == intrinsic_UnsafeGetElement) + return inlineUnsafeGetElement(callInfo, GetElem_Unsafe); + if (native == intrinsic_UnsafeGetImmutableElement) + return inlineUnsafeGetElement(callInfo, GetElem_UnsafeImmutable); if (native == intrinsic_NewDenseArray) return inlineNewDenseArray(callInfo); @@ -952,9 +956,10 @@ IonBuilder::inlineUnsafeSetElement(CallInfo &callInfo) /* Important: * * Here we inline each of the stores resulting from a call to - * %UnsafeSetElement(). It is essential that these stores occur + * UnsafeSetElement(). It is essential that these stores occur * atomically and cannot be interrupted by a stack or recursion * check. If this is not true, race conditions can occur. + * See definition of UnsafeSetElement() for more details. */ for (uint32_t base = 0; base < argc; base += 3) { @@ -1053,6 +1058,30 @@ IonBuilder::inlineUnsafeSetTypedArrayElement(CallInfo &callInfo, return true; } +IonBuilder::InliningStatus +IonBuilder::inlineUnsafeGetElement(CallInfo &callInfo, + GetElemSafety safety) +{ + JS_ASSERT(safety != GetElem_Normal); + + uint32_t argc = callInfo.argc(); + if (argc < 2 || callInfo.constructing()) + return InliningStatus_NotInlined; + const uint32_t obj = 0; + const uint32_t index = 1; + if (!ElementAccessIsDenseNative(callInfo.getArg(obj), + callInfo.getArg(index))) + return InliningStatus_NotInlined; + if (ElementAccessHasExtraIndexedProperty(cx, callInfo.getArg(obj))) + return InliningStatus_NotInlined; + callInfo.unwrapArgs(); + if (!jsop_getelem_dense(safety, + callInfo.getArg(obj), + callInfo.getArg(index))) + return InliningStatus_Error; + return InliningStatus_Inlined; +} + IonBuilder::InliningStatus IonBuilder::inlineForceSequentialOrInParallelSection(CallInfo &callInfo) { diff --git a/js/src/ion/MIR.h b/js/src/ion/MIR.h index 4450915e2a9c..3a36021cb223 100644 --- a/js/src/ion/MIR.h +++ b/js/src/ion/MIR.h @@ -4510,11 +4510,13 @@ class MLoadElement { bool needsHoleCheck_; bool loadDoubles_; + bool knownImmutable_; // load of data that is known to be immutable - MLoadElement(MDefinition *elements, MDefinition *index, bool needsHoleCheck, bool loadDoubles) + MLoadElement(MDefinition *elements, MDefinition *index, bool needsHoleCheck, bool loadDoubles, bool knownImmutable) : MBinaryInstruction(elements, index), needsHoleCheck_(needsHoleCheck), - loadDoubles_(loadDoubles) + loadDoubles_(loadDoubles), + knownImmutable_(knownImmutable) { setResultType(MIRType_Value); setMovable(); @@ -4526,8 +4528,10 @@ class MLoadElement INSTRUCTION_HEADER(LoadElement) static MLoadElement *New(MDefinition *elements, MDefinition *index, - bool needsHoleCheck, bool loadDoubles) { - return new MLoadElement(elements, index, needsHoleCheck, loadDoubles); + bool needsHoleCheck, bool loadDoubles, + bool knownImmutable) { + return new MLoadElement(elements, index, needsHoleCheck, loadDoubles, + knownImmutable); } TypePolicy *typePolicy() { @@ -4549,6 +4553,9 @@ class MLoadElement return needsHoleCheck(); } AliasSet getAliasSet() const { + if (knownImmutable_) + return AliasSet::None(); + return AliasSet::Load(AliasSet::Element); } }; diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 1a01b6cda11d..337eaa2bd899 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -2360,6 +2360,9 @@ JSBool intrinsic_IsCallable(JSContext *cx, unsigned argc, Value *vp); JSBool intrinsic_ThrowError(JSContext *cx, unsigned argc, Value *vp); JSBool intrinsic_NewDenseArray(JSContext *cx, unsigned argc, Value *vp); JSBool intrinsic_UnsafeSetElement(JSContext *cx, unsigned argc, Value *vp); +JSBool intrinsic_UnsafeGetElement(JSContext *cx, unsigned argc, Value *vp); +JSBool intrinsic_UnsafeGetImmutableElement(JSContext *cx, unsigned argc, + Value *vp); JSBool intrinsic_ShouldForceSequential(JSContext *cx, unsigned argc, Value *vp); JSBool intrinsic_NewParallelArray(JSContext *cx, unsigned argc, Value *vp); diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index a3f7798046d8..20addd06ae27 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -341,15 +341,26 @@ js::intrinsic_NewDenseArray(JSContext *cx, unsigned argc, Value *vp) /* * UnsafeSetElement(arr0, idx0, elem0, ..., arrN, idxN, elemN): For * each set of (arr, idx, elem) arguments that are passed, performs - * the assignment |arr[idx] = elem|. |arr| must be either a dense array + * the assignment `arr[idx] = elem`. `arr` must be either a dense array * or a typed array. * - * If |arr| is a dense array, the index must be an int32 less than the - * initialized length of |arr|. Use |%EnsureDenseResultArrayElements| - * to ensure that the initialized length is long enough. + * If `arr` is a dense array, the index must be an int32 less than the + * initialized length of `arr`. Use `NewDenseAllocatedArray` to ensure + * that the initialized length is long enough. * - * If |arr| is a typed array, the index must be an int32 less than the - * length of |arr|. + * If `arr` is a typed array, the index must be an int32 less than the + * length of `arr`. + * + * The reason that `UnsafeSetElement` takes multiple + * array/index/element triples is not for convenience but rather for + * semantic reasons: there are a few places in the parallel code where + * correctness relies on the fact that *all of the assignments occur + * or none of them*. This occurs in operations like reduce or fold + * which mutate the same data in place. That is, we do not want to + * bail out or interrupt in between the individual assignments. To + * convey this notion, we place all the assignments together into one + * `UnsafeSetElement` call. It is preferable to use multiple calls if + * it is not important that the assignments occur all-or-nothing. */ JSBool js::intrinsic_UnsafeSetElement(JSContext *cx, unsigned argc, Value *vp) @@ -380,7 +391,6 @@ js::intrinsic_UnsafeSetElement(JSContext *cx, unsigned argc, Value *vp) } else { JS_ASSERT(idx < TypedArray::length(arrobj)); RootedValue tmp(cx, args[elemi]); - // XXX: Always non-strict. if (!JSObject::setElement(cx, arrobj, arrobj, idx, &tmp, false)) return false; } @@ -390,6 +400,46 @@ js::intrinsic_UnsafeSetElement(JSContext *cx, unsigned argc, Value *vp) return true; } +/* + * UnsafeGetElement(arr, idx)=elem: + * + * Loads an element from an array. Requires that `arr` be a dense + * array and `idx` be in bounds. In ion compiled code, no bounds + * check will be emitted. + */ +JSBool +js::intrinsic_UnsafeGetElement(JSContext *cx, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + + const uint32_t arri = 0; + const uint32_t idxi = 1; + + JS_ASSERT(args[arri].isObject()); + JS_ASSERT(args[idxi].isInt32()); + + RootedObject arrobj(cx, &args[arri].toObject()); + uint32_t idx = args[idxi].toInt32(); + + JS_ASSERT(args[arri].toObject().isNative()); + JS_ASSERT(idx < arrobj->getDenseInitializedLength()); + args.rval().set(arrobj->getDenseElement(idx)); + return true; +} + +/* + * UnsafeGetImmutableElement(arr, idx)=elem: + * + * Same as `UnsafeGetElement(arr, idx)`, except that the array is + * known by the self-hosting code to be immutable. Therefore, ion + * compilation can reorder this load freely with respect to stores. + */ +JSBool +js::intrinsic_UnsafeGetImmutableElement(JSContext *cx, unsigned argc, Value *vp) +{ + return intrinsic_UnsafeGetElement(cx, argc, vp); +} + /* * ParallelTestsShouldPass(): Returns false if we are running in a * mode (such as --ion-eager) that is known to cause additional @@ -468,6 +518,8 @@ const JSFunctionSpec intrinsic_functions[] = { JS_FN("NewParallelArray", intrinsic_NewParallelArray, 3,0), JS_FN("NewDenseArray", intrinsic_NewDenseArray, 1,0), JS_FN("UnsafeSetElement", intrinsic_UnsafeSetElement, 3,0), + JS_FN("UnsafeGetElement", intrinsic_UnsafeGetElement, 2,0), + JS_FN("UnsafeGetImmutableElement", intrinsic_UnsafeGetImmutableElement, 2,0), JS_FN("ShouldForceSequential", intrinsic_ShouldForceSequential, 0,0), JS_FN("ParallelTestsShouldPass", intrinsic_ParallelTestsShouldPass, 0,0), From 196a0e94e43a5b4649cda54de0e750fde738cf51 Mon Sep 17 00:00:00 2001 From: Shelly Lin Date: Fri, 14 Jun 2013 15:16:41 +0800 Subject: [PATCH 09/84] Bug 882956 - Fix WebAudio stack-buffer-overflow crash. r=ehsan. --- content/media/AudioSegment.cpp | 2 +- content/media/AudioSegment.h | 6 ++++-- content/media/test/crashtests/882956.html | 15 +++++++++++++++ content/media/test/crashtests/crashtests.list | 1 + 4 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 content/media/test/crashtests/882956.html diff --git a/content/media/AudioSegment.cpp b/content/media/AudioSegment.cpp index 7ccce0d8138d..03e6d5691b5e 100644 --- a/content/media/AudioSegment.cpp +++ b/content/media/AudioSegment.cpp @@ -171,7 +171,7 @@ AudioSegment::WriteTo(AudioStream* aOutput) if (channelData.Length() > outputChannels) { // Down-mix. DownmixAndInterleave(channelData, c.mBufferFormat, duration, - c.mVolume, channelData.Length(), buf.Elements()); + c.mVolume, outputChannels, buf.Elements()); } else { InterleaveAndConvertBuffer(channelData.Elements(), c.mBufferFormat, duration, c.mVolume, diff --git a/content/media/AudioSegment.h b/content/media/AudioSegment.h index 3ff5b70f326c..7000dc82f2bb 100644 --- a/content/media/AudioSegment.h +++ b/content/media/AudioSegment.h @@ -30,9 +30,11 @@ void InterleaveAndConvertBuffer(const void** aSourceChannels, int32_t aLength, float aVolume, int32_t aChannels, AudioDataValue* aOutput); + /** - * Down-mix audio channels, and interleave the channel data. A total of - * aOutputChannels*aDuration interleaved samples will be stored into aOutput. + * Given an array of input channels (aChannelData), downmix to aOutputChannels, + * interleave the channel data. A total of aOutputChannels*aDuration + * interleaved samples will be copied to a channel buffer in aOutput. */ void DownmixAndInterleave(const nsTArray& aChannelData, AudioSampleFormat aSourceFormat, int32_t aDuration, diff --git a/content/media/test/crashtests/882956.html b/content/media/test/crashtests/882956.html new file mode 100644 index 000000000000..ae7b441f9993 --- /dev/null +++ b/content/media/test/crashtests/882956.html @@ -0,0 +1,15 @@ + diff --git a/content/media/test/crashtests/crashtests.list b/content/media/test/crashtests/crashtests.list index 95a9a9350263..3ea3632778c4 100644 --- a/content/media/test/crashtests/crashtests.list +++ b/content/media/test/crashtests/crashtests.list @@ -46,3 +46,4 @@ load 880384.html load 880404.html load 880724.html load 881775.html +load 882956.html From fa1f6986fde6eb9e1b044c389f701a7e574b9195 Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Fri, 14 Jun 2013 05:58:28 -0600 Subject: [PATCH 10/84] Bug 678037 - Enable lazy JS parsing and fix various bugs, r=waldo,evilpie,nobody. --- js/src/frontend/BytecodeCompiler.cpp | 71 ++++++++----- js/src/frontend/BytecodeEmitter.cpp | 22 +++- js/src/frontend/NameFunctions.cpp | 4 +- js/src/frontend/Parser.cpp | 84 ++++++++++----- js/src/frontend/SharedContext.h | 4 + js/src/frontend/SyntaxParseHandler.h | 11 +- js/src/frontend/TokenStream.cpp | 5 +- js/src/frontend/TokenStream.h | 8 +- js/src/ion/AsmJS.cpp | 2 +- js/src/ion/BaselineIC.cpp | 3 + js/src/ion/CodeGenerator.cpp | 4 + js/src/ion/IonBuilder.cpp | 2 + js/src/ion/ParallelArrayAnalysis.cpp | 8 +- js/src/ion/ParallelFunctions.cpp | 2 + js/src/jit-test/tests/basic/functionnames.js | 4 +- js/src/jit-test/tests/basic/lazyparse.js | 36 +++++++ .../basic/testOOMInAutoEnterCompartment.js | 9 +- js/src/jsapi.cpp | 4 +- js/src/jsapi.h | 2 +- js/src/jscompartment.cpp | 79 +++++++++++++- js/src/jsfun.cpp | 25 +++-- js/src/jsfun.h | 9 -- js/src/jsgc.cpp | 6 +- js/src/jsgc.h | 2 +- js/src/jsinferinlines.h | 32 +++--- js/src/jsscript.cpp | 93 +++++++++++++--- js/src/jsscript.h | 100 ++++++++++-------- js/src/vm/Debugger.cpp | 22 ---- 28 files changed, 447 insertions(+), 206 deletions(-) create mode 100644 js/src/jit-test/tests/basic/lazyparse.js diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index 862fb8f8a7d3..215dcc6389a0 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -74,6 +74,15 @@ CheckArgumentsWithinEval(JSContext *cx, Parser &parser, Handle return true; } +inline bool +CanLazilyParse(JSContext *cx, const CompileOptions &options) +{ + return options.canLazilyParse && + options.compileAndGo && + options.sourcePolicy == CompileOptions::SAVE_SOURCE && + !cx->compartment()->debugMode(); +} + JSScript * frontend::CompileScript(JSContext *cx, HandleObject scopeChain, HandleScript evalCaller, @@ -102,7 +111,7 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain, return NULL; if (options.filename && !ss->setFilename(cx, options.filename)) return NULL; - + JS::RootedScriptSource sourceObject(cx, ScriptSourceObject::create(cx, ss)); if (!sourceObject) return NULL; @@ -120,28 +129,21 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain, break; } + bool canLazilyParse = CanLazilyParse(cx, options); + Maybe > syntaxParser; - if (options.canLazilyParse) { + if (canLazilyParse) { syntaxParser.construct(cx, options, chars, length, /* foldConstants = */ false, (Parser *) NULL, (LazyScript *) NULL); } Parser parser(cx, options, chars, length, /* foldConstants = */ true, - options.canLazilyParse ? &syntaxParser.ref() : NULL, NULL); + canLazilyParse ? &syntaxParser.ref() : NULL, NULL); parser.sct = sct; GlobalSharedContext globalsc(cx, scopeChain, StrictModeFromContext(cx)); - // Syntax parsing may cause us to restart processing of top level - // statements in the script. Use Maybe<> so that the parse context can be - // reset when this occurs. - Maybe > pc; - - pc.construct(&parser, (GenericParseContext *) NULL, &globalsc, staticLevel, /* bodyid = */ 0); - if (!pc.ref().init()) - return NULL; - bool savedCallerFun = options.compileAndGo && evalCaller && @@ -169,6 +171,15 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain, if (!bce.init()) return NULL; + // Syntax parsing may cause us to restart processing of top level + // statements in the script. Use Maybe<> so that the parse context can be + // reset when this occurs. + Maybe > pc; + + pc.construct(&parser, (GenericParseContext *) NULL, &globalsc, staticLevel, /* bodyid = */ 0); + if (!pc.ref().init()) + return NULL; + /* If this is a direct call to eval, inherit the caller's strictness. */ if (evalCaller && evalCaller->strict) globalsc.strict = true; @@ -313,32 +324,34 @@ bool frontend::CompileLazyFunction(JSContext *cx, HandleFunction fun, LazyScript *lazy, const jschar *chars, size_t length) { - CompileOptions options(cx); + JS_ASSERT(cx->compartment() == fun->compartment()); + + CompileOptions options(cx, lazy->version()); options.setPrincipals(cx->compartment()->principals) - .setOriginPrincipals(lazy->parent()->originPrincipals) - .setVersion(lazy->parent()->getVersion()) - .setFileAndLine(lazy->parent()->filename(), lazy->lineno()) + .setOriginPrincipals(lazy->originPrincipals()) + .setFileAndLine(lazy->source()->filename(), lazy->lineno()) .setColumn(lazy->column()) - .setCompileAndGo(lazy->parent()->compileAndGo) + .setCompileAndGo(true) .setNoScriptRval(false) .setSelfHostingMode(false); Parser parser(cx, options, chars, length, /* foldConstants = */ true, NULL, lazy); - RootedObject enclosingScope(cx, lazy->parent()->function()); + RootedObject enclosingScope(cx, lazy->parentFunction()); - ParseNode *pn = parser.standaloneLazyFunction(fun, lazy->parent()->staticLevel + 1, - lazy->strict()); + ParseNode *pn = parser.standaloneLazyFunction(fun, lazy->staticLevel(), lazy->strict()); if (!pn) return false; - JS::RootedScriptSource sourceObject(cx, ScriptSourceObject::create(cx, lazy->source())); - if (!sourceObject) + if (!NameFunctions(cx, pn)) return false; + JS::RootedScriptSource sourceObject(cx, lazy->sourceObject()); + JS_ASSERT(sourceObject); + Rooted script(cx, JSScript::Create(cx, enclosingScope, false, - options, lazy->parent()->staticLevel + 1, + options, lazy->staticLevel(), sourceObject, lazy->begin(), lazy->end())); if (!script) return false; @@ -347,11 +360,11 @@ frontend::CompileLazyFunction(JSContext *cx, HandleFunction fun, LazyScript *laz if (lazy->directlyInsideEval()) script->directlyInsideEval = true; - - bool hasGlobalScope = lazy->parent()->compileAndGo; + if (lazy->usesArgumentsAndApply()) + script->usesArgumentsAndApply = true; BytecodeEmitter bce(/* parent = */ NULL, &parser, pn->pn_funbox, script, options.forEval, - /* evalCaller = */ NullPtr(), hasGlobalScope, + /* evalCaller = */ NullPtr(), /* hasGlobalScope = */ true, options.lineno, BytecodeEmitter::LazyFunction); if (!bce.init()) return false; @@ -385,8 +398,10 @@ frontend::CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, CompileO return false; } + bool canLazilyParse = CanLazilyParse(cx, options); + Maybe > syntaxParser; - if (options.canLazilyParse) { + if (canLazilyParse) { syntaxParser.construct(cx, options, chars, length, /* foldConstants = */ false, (Parser *) NULL, (LazyScript *) NULL); @@ -395,7 +410,7 @@ frontend::CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, CompileO JS_ASSERT(!options.forEval); Parser parser(cx, options, chars, length, /* foldConstants = */ true, - options.canLazilyParse ? &syntaxParser.ref() : NULL, NULL); + canLazilyParse ? &syntaxParser.ref() : NULL, NULL); parser.sct = &sct; JS_ASSERT(fun); diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 5a07cd3e21b8..a31cb3593d44 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -1128,11 +1128,22 @@ TryConvertFreeName(BytecodeEmitter *bce, ParseNode *pn) * resolving upvar accesses within the inner function. */ if (bce->emitterMode == BytecodeEmitter::LazyFunction) { + // The only statements within a lazy function which can push lexical + // scopes are try/catch blocks. Use generic ops in this case. + for (StmtInfoBCE *stmt = bce->topStmt; stmt; stmt = stmt->down) { + switch (stmt->type) { + case STMT_TRY: + case STMT_FINALLY: + return true; + default:; + } + } + size_t hops = 0; FunctionBox *funbox = bce->sc->asFunctionBox(); if (funbox->hasExtensibleScope()) return false; - if (funbox->function()->atom() == pn->pn_atom) + if (funbox->function()->isNamedLambda() && funbox->function()->atom() == pn->pn_atom) return false; if (funbox->function()->isHeavyweight()) { hops++; @@ -4491,8 +4502,10 @@ EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) return false; if (fun->isInterpretedLazy()) { - if (!fun->lazyScript()->parent()) - fun->lazyScript()->initParent(bce->script); + if (!fun->lazyScript()->sourceObject()) { + JSFunction *parent = bce->sc->isFunctionBox() ? bce->sc->asFunctionBox()->function() : NULL; + fun->lazyScript()->setParent(parent, bce->script->sourceObject(), bce->script->originPrincipals); + } } else { SharedContext *outersc = bce->sc; @@ -4557,6 +4570,9 @@ EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) /* We measured the max scope depth when we parsed the function. */ if (!EmitFunctionScript(cx, &bce2, pn->pn_body)) return false; + + if (funbox->usesArguments && funbox->usesApply) + script->usesArgumentsAndApply = true; } } diff --git a/js/src/frontend/NameFunctions.cpp b/js/src/frontend/NameFunctions.cpp index 109f22ce47c9..76f55000eab7 100644 --- a/js/src/frontend/NameFunctions.cpp +++ b/js/src/frontend/NameFunctions.cpp @@ -175,8 +175,6 @@ class NameResolver JSAtom *resolveFun(ParseNode *pn, HandleAtom prefix) { JS_ASSERT(pn != NULL && pn->isKind(PNK_FUNCTION)); RootedFunction fun(cx, pn->pn_funbox->function()); - if (nparents == 0) - return NULL; StringBuffer buf(cx); this->buf = &buf; @@ -184,7 +182,7 @@ class NameResolver /* If the function already has a name, use that */ if (fun->displayAtom() != NULL) { if (prefix == NULL) - return fun->atom(); + return fun->displayAtom(); if (!buf.append(prefix) || !buf.append("/") || !buf.append(fun->displayAtom())) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 97580b021f3f..22805ff9995c 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -419,9 +419,6 @@ Parser::Parser(JSContext *cx, const CompileOptions &options, abortedSyntaxParse(false), handler(cx, tokenStream, foldConstants, syntaxParser, lazyOuterFunction) { - // XXX bug 678037 always disable syntax parsing for now. - handler.disableSyntaxParser(); - cx->runtime()->activeCompilations++; // The Mozilla specific JSOPTION_EXTRA_WARNINGS option adds extra warnings @@ -487,6 +484,8 @@ FunctionBox::FunctionBox(JSContext *cx, ObjectBox* traceListHead, JSFunction *fu inGenexpLambda(false), useAsm(false), insideUseAsm(outerpc && outerpc->useAsmOrInsideUseAsm()), + usesArguments(false), + usesApply(false), funCxFlags() { JS_ASSERT(fun->isTenured()); @@ -925,6 +924,7 @@ Parser::checkFunctionArguments() dn->pn_dflags |= PND_IMPLICITARGUMENTS; if (!pc->define(context, arguments, dn, Definition::VAR)) return false; + pc->sc->asFunctionBox()->usesArguments = true; break; } } @@ -1014,11 +1014,15 @@ template <> bool Parser::checkFunctionArguments() { - if (pc->sc->asFunctionBox()->function()->hasRest()) { - if (pc->lexdeps->lookup(context->names().arguments)) { + bool hasRest = pc->sc->asFunctionBox()->function()->hasRest(); + + if (pc->lexdeps->lookup(context->names().arguments)) { + pc->sc->asFunctionBox()->usesArguments = true; + if (hasRest) { report(ParseError, false, null(), JSMSG_ARGUMENTS_AND_REST); return false; } + } else if (hasRest) { DefinitionNode maybeArgDef = pc->decls().lookupFirst(context->names().arguments); if (maybeArgDef && handler.getDefinitionKind(maybeArgDef) != Definition::ARG) { report(ParseError, false, null(), JSMSG_ARGUMENTS_AND_REST); @@ -1341,14 +1345,6 @@ Parser::leaveFunction(ParseNode *fn, HandlePropertyName funNam continue; } - /* - * If there are no uses of this placeholder (e.g., it was created - * for an identifierName that turned out to be a label), there is - * nothing left to do. - */ - if (!dn->dn_uses) - continue; - Definition *outer_dn = outerpc->decls().lookupFirst(atom); /* @@ -2046,7 +2042,7 @@ Parser::finishFunctionDefinition(Node pn, FunctionBox *funbo size_t numFreeVariables = pc->lexdeps->count(); size_t numInnerFunctions = pc->innerFunctions.length(); - LazyScript *lazy = LazyScript::Create(context, numFreeVariables, numInnerFunctions, + LazyScript *lazy = LazyScript::Create(context, numFreeVariables, numInnerFunctions, versionNumber(), funbox->bufStart, funbox->bufEnd, funbox->startLine, funbox->startColumn); if (!lazy) @@ -2064,6 +2060,8 @@ Parser::finishFunctionDefinition(Node pn, FunctionBox *funbo if (pc->sc->strict) lazy->setStrict(); + if (funbox->usesArguments && funbox->usesApply) + lazy->setUsesArgumentsAndApply(); PropagateTransitiveParseFlags(funbox, lazy); funbox->object->toFunction()->initLazyScript(lazy); @@ -2173,6 +2171,11 @@ Parser::functionArgsAndBody(Node pn, HandleFunction fun, *becameStrict = false; ParseContext *outerpc = pc; + // As from a full parse handler, abort if functions are defined within + // lexical scopes. + if (pc->topScopeStmt) + return abortIfSyntaxParser(); + // Create box for fun->object early to protect against last-ditch GC. FunctionBox *funbox = newFunctionBox(fun, pc, strict); if (!funbox) @@ -4099,6 +4102,7 @@ Parser::forStatement() /* Check that the left side of the 'in' or 'of' is valid. */ if (!forDecl && lhsNode != SyntaxParseHandler::NodeName && + lhsNode != SyntaxParseHandler::NodeGetProp && lhsNode != SyntaxParseHandler::NodeLValue) { JS_ALWAYS_FALSE(abortIfSyntaxParser()); @@ -4311,12 +4315,15 @@ Parser::tryStatement() return pn; } -template -typename ParseHandler::Node -Parser::withStatement() +template <> +ParseNode * +Parser::withStatement() { - if (!abortIfSyntaxParser()) + if (handler.syntaxParser) { + handler.disableSyntaxParser(); + abortedSyntaxParse = true; return null(); + } JS_ASSERT(tokenStream.isCurrentTokenType(TOK_WITH)); uint32_t begin = tokenStream.currentToken().pos.begin; @@ -4354,7 +4361,7 @@ Parser::withStatement() * to safely optimize binding globals (see bug 561923). */ for (AtomDefnRange r = pc->lexdeps->all(); !r.empty(); r.popFront()) { - DefinitionNode defn = r.front().value().get(); + DefinitionNode defn = r.front().value().get(); DefinitionNode lexdep = handler.resolve(defn); handler.deoptimizeUsesWithin(lexdep, TokenPos::make(begin, tokenStream.currentToken().pos.begin)); @@ -4369,6 +4376,14 @@ Parser::withStatement() return pn; } +template <> +SyntaxParseHandler::Node +Parser::withStatement() +{ + JS_ALWAYS_FALSE(abortIfSyntaxParser()); + return null(); +} + #if JS_HAS_BLOCK_SCOPE template <> ParseNode * @@ -5235,8 +5250,12 @@ bool Parser::setAssignmentLhsOps(Node pn, JSOp op) { /* Full syntax checking of valid assignment LHS terms requires a parse tree. */ - if (pn != SyntaxParseHandler::NodeName && pn != SyntaxParseHandler::NodeLValue) + if (pn != SyntaxParseHandler::NodeName && + pn != SyntaxParseHandler::NodeGetProp && + pn != SyntaxParseHandler::NodeLValue) + { return abortIfSyntaxParser(); + } return checkStrictAssignment(pn); } @@ -5419,8 +5438,12 @@ Parser::checkDeleteExpression(Node *pn) // Treat deletion of non-lvalues as ambiguous, so that any error associated // with deleting a call expression is reported. - if (*pn != SyntaxParseHandler::NodeLValue && strictMode()) + if (*pn != SyntaxParseHandler::NodeGetProp && + *pn != SyntaxParseHandler::NodeLValue && + strictMode()) + { return abortIfSyntaxParser(); + } return true; } @@ -6444,10 +6467,13 @@ Parser::memberExpr(TokenKind tt, bool allowCallSyntax) } } else if (JSAtom *atom = handler.isGetProp(lhs)) { /* Select JSOP_FUNAPPLY given foo.apply(...). */ - if (atom == context->names().apply) + if (atom == context->names().apply) { handler.setOp(nextMember, JSOP_FUNAPPLY); - else if (atom == context->names().call) + if (pc->sc->isFunctionBox()) + pc->sc->asFunctionBox()->usesApply = true; + } else if (atom == context->names().call) { handler.setOp(nextMember, JSOP_FUNCALL); + } } handler.setBeginPosition(nextMember, lhs); @@ -6551,7 +6577,17 @@ template <> SyntaxParseHandler::Node Parser::newRegExp(const jschar *buf, size_t length, RegExpFlag flags) { - return SyntaxParseHandler::NodeGeneric; + // Create the regexp even when doing a syntax parse, to check the regexp's syntax. + const StableCharPtr chars(buf, length); + RegExpStatics *res = context->regExpStatics(); + + RegExpObject *reobj; + if (context->hasfp()) + reobj = RegExpObject::create(context, res, chars.get(), length, flags, &tokenStream); + else + reobj = RegExpObject::createNoStatics(context, chars.get(), length, flags, &tokenStream); + + return reobj ? SyntaxParseHandler::NodeGeneric : SyntaxParseHandler::NodeFailure; } template diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h index ae17cf1e3a2e..3b6d02cfc322 100644 --- a/js/src/frontend/SharedContext.h +++ b/js/src/frontend/SharedContext.h @@ -210,6 +210,10 @@ class FunctionBox : public ObjectBox, public SharedContext bool useAsm:1; /* function contains "use asm" directive */ bool insideUseAsm:1; /* nested function of function of "use asm" directive */ + // Fields for use in heuristics. + bool usesArguments:1; /* contains a free use of 'arguments' */ + bool usesApply:1; /* contains an f.apply() call */ + FunctionContextFlags funCxFlags; template diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index 19f411f5becc..a4e963f28318 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -32,6 +32,7 @@ class SyntaxParseHandler NodeFailure = 0, NodeGeneric, NodeName, + NodeGetProp, NodeString, NodeStringExprStatement, NodeLValue @@ -102,7 +103,11 @@ class SyntaxParseHandler return NodeGeneric; } Node newDebuggerStatement(const TokenPos &pos) { return NodeGeneric; } - Node newPropertyAccess(Node pn, PropertyName *name, uint32_t end) { return NodeLValue; } + Node newPropertyAccess(Node pn, PropertyName *name, uint32_t end) + { + lastAtom = name; + return NodeGetProp; + } Node newPropertyByValue(Node pn, Node kid, uint32_t end) { return NodeLValue; } bool addCatchBlock(Node catchList, Node letBlock, @@ -159,7 +164,9 @@ class SyntaxParseHandler PropertyName *isName(Node pn) { return (pn == NodeName) ? lastAtom->asPropertyName() : NULL; } - PropertyName *isGetProp(Node pn) { return NULL; } + PropertyName *isGetProp(Node pn) { + return (pn == NodeGetProp) ? lastAtom->asPropertyName() : NULL; + } JSAtom *isStringExprStatement(Node pn, TokenPos *pos) { if (pn == NodeStringExprStatement) { *pos = lastStringPos; diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index e658b8bbef78..6c83d6434afa 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -557,7 +557,7 @@ TokenStream::advance(size_t position) void TokenStream::tell(Position *pos) { - pos->buf = userbuf.addressOfNextRawChar(); + pos->buf = userbuf.addressOfNextRawChar(/* allowPoisoned = */ true); pos->flags = flags; pos->lineno = lineno; pos->linebase = linebase; @@ -571,7 +571,7 @@ TokenStream::tell(Position *pos) void TokenStream::seek(const Position &pos) { - userbuf.setAddressOfNextRawChar(pos.buf); + userbuf.setAddressOfNextRawChar(pos.buf, /* allowPoisoned = */ true); flags = pos.flags; lineno = pos.lineno; linebase = pos.linebase; @@ -587,6 +587,7 @@ void TokenStream::seek(const Position &pos, const TokenStream &other) { srcCoords.fill(other.srcCoords); + lastFunctionKeyword = other.lastFunctionKeyword; seek(pos); } diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index 941b6401dbe3..278a2360cc3e 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -832,14 +832,14 @@ class MOZ_STACK_CLASS TokenStream ptr--; } - const jschar *addressOfNextRawChar() const { - JS_ASSERT(ptr); /* make sure haven't been poisoned */ + const jschar *addressOfNextRawChar(bool allowPoisoned = false) const { + JS_ASSERT_IF(!allowPoisoned, ptr); /* make sure haven't been poisoned */ return ptr; } /* Use this with caution! */ - void setAddressOfNextRawChar(const jschar *a) { - JS_ASSERT(a); + void setAddressOfNextRawChar(const jschar *a, bool allowPoisoned = false) { + JS_ASSERT_IF(!allowPoisoned, a); ptr = a; } diff --git a/js/src/ion/AsmJS.cpp b/js/src/ion/AsmJS.cpp index 378ae3f3c412..1686ac240c3c 100644 --- a/js/src/ion/AsmJS.cpp +++ b/js/src/ion/AsmJS.cpp @@ -6264,7 +6264,7 @@ AsmJSModule::~AsmJSModule() if (!exitDatum.fun) continue; - if (!exitDatum.fun->isInterpreted()) + if (!exitDatum.fun->hasScript()) continue; JSScript *script = exitDatum.fun->nonLazyScript(); diff --git a/js/src/ion/BaselineIC.cpp b/js/src/ion/BaselineIC.cpp index 871d92018b37..6a5fcb9f188c 100644 --- a/js/src/ion/BaselineIC.cpp +++ b/js/src/ion/BaselineIC.cpp @@ -1324,6 +1324,9 @@ ICUpdatedStub::addUpdateStubForValue(JSContext *cx, HandleScript script, HandleO return true; } + if (!obj->getType(cx)) + return false; + types::EnsureTrackPropertyTypes(cx, obj, id); if (val.isPrimitive()) { diff --git a/js/src/ion/CodeGenerator.cpp b/js/src/ion/CodeGenerator.cpp index 53e18ba9d6c7..a8b5b8df7eb4 100644 --- a/js/src/ion/CodeGenerator.cpp +++ b/js/src/ion/CodeGenerator.cpp @@ -1694,6 +1694,10 @@ CodeGenerator::visitCallKnown(LCallKnown *call) return true; } + // The calleereg is known to be a non-native function, but might point to + // a LazyScript instead of a JSScript. + masm.branchIfFunctionHasNoScript(calleereg, &uncompiled); + // Knowing that calleereg is a non-native function, load the JSScript. masm.loadPtr(Address(calleereg, JSFunction::offsetOfNativeOrScript()), objreg); diff --git a/js/src/ion/IonBuilder.cpp b/js/src/ion/IonBuilder.cpp index 4d35f622915a..defa2286ded3 100644 --- a/js/src/ion/IonBuilder.cpp +++ b/js/src/ion/IonBuilder.cpp @@ -200,6 +200,8 @@ IonBuilder::getPolyCallTargets(types::StackTypeSet *calleeTypes, targets.clear(); return true; } + if (!typeObj->interpretedFunction->getOrCreateScript(cx)) + return false; DebugOnly appendOk = targets.append(typeObj->interpretedFunction); JS_ASSERT(appendOk); diff --git a/js/src/ion/ParallelArrayAnalysis.cpp b/js/src/ion/ParallelArrayAnalysis.cpp index 3a34014bda1c..84b40624a1f2 100644 --- a/js/src/ion/ParallelArrayAnalysis.cpp +++ b/js/src/ion/ParallelArrayAnalysis.cpp @@ -856,14 +856,18 @@ GetPossibleCallees(JSContext *cx, if (!rootedFun->isInterpreted()) continue; - if (rootedFun->nonLazyScript()->shouldCloneAtCallsite) { + rootedScript = rootedFun->getOrCreateScript(cx); + if (!rootedScript) + return false; + + if (rootedScript->shouldCloneAtCallsite) { rootedFun = CloneFunctionAtCallsite(cx, rootedFun, script, pc); if (!rootedFun) return false; + rootedScript = rootedFun->nonLazyScript(); } // check if this call target is already known - rootedScript = rootedFun->nonLazyScript(); if (!AddCallTarget(rootedScript, targets)) return false; } diff --git a/js/src/ion/ParallelFunctions.cpp b/js/src/ion/ParallelFunctions.cpp index c1572f07ce29..f05894ac1490 100644 --- a/js/src/ion/ParallelFunctions.cpp +++ b/js/src/ion/ParallelFunctions.cpp @@ -434,6 +434,8 @@ ion::ParCallToUncompiledScript(JSFunction *func) JSScript *script = func->nonLazyScript(); Spew(SpewBailouts, "Call to uncompiled script: %p:%s:%d", script, script->filename(), script->lineno); + } else if (func->isInterpretedLazy()) { + Spew(SpewBailouts, "Call to uncompiled lazy script"); } else if (func->isBoundFunction()) { int depth = 0; JSFunction *target = func->getBoundFunctionTarget()->toFunction(); diff --git a/js/src/jit-test/tests/basic/functionnames.js b/js/src/jit-test/tests/basic/functionnames.js index 1f89047143eb..92fbf258c634 100644 --- a/js/src/jit-test/tests/basic/functionnames.js +++ b/js/src/jit-test/tests/basic/functionnames.js @@ -36,7 +36,7 @@ var Foo = function (){ assertName(arguments.callee, 'Foo<') return function(){}; }(); -assertName(Foo, 'Foo'); +assertName(Foo, 'Foo:( + foo = evalcx("(function foo() { foo.bar() })"); + foo.bar = evalcx("(function bar() {})"); + + fatty(); +} diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 828bd264e51b..b3f120e12c56 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -5289,10 +5289,10 @@ AutoFile::open(JSContext *cx, const char *filename) } -JS::CompileOptions::CompileOptions(JSContext *cx) +JS::CompileOptions::CompileOptions(JSContext *cx, JSVersion version) : principals(NULL), originPrincipals(NULL), - version(cx->findVersion()), + version(version != JSVERSION_UNKNOWN ? version : cx->findVersion()), versionSet(false), utf8(false), filename(NULL), diff --git a/js/src/jsapi.h b/js/src/jsapi.h index fb8790bdef0f..f3c62a1d825d 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -3907,7 +3907,7 @@ struct JS_PUBLIC_API(CompileOptions) { SAVE_SOURCE } sourcePolicy; - explicit CompileOptions(JSContext *cx); + explicit CompileOptions(JSContext *cx, JSVersion version = JSVERSION_UNKNOWN); CompileOptions &setPrincipals(JSPrincipals *p) { principals = p; return *this; } CompileOptions &setOriginPrincipals(JSPrincipals *p) { originPrincipals = p; return *this; } CompileOptions &setVersion(JSVersion v) { version = v; versionSet = true; return *this; } diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index 48b8459d7890..63074e509eed 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -603,6 +603,77 @@ JSCompartment::hasScriptsOnStack() return false; } +static bool +AddInnerLazyFunctionsFromScript(JSScript *script, AutoObjectVector &lazyFunctions) +{ + if (!script->hasObjects()) + return true; + ObjectArray *objects = script->objects(); + for (size_t i = script->innerObjectsStart(); i < objects->length; i++) { + JSObject *obj = objects->vector[i]; + if (obj->isFunction() && obj->toFunction()->isInterpretedLazy()) { + if (!lazyFunctions.append(obj)) + return false; + } + } + return true; +} + +static bool +CreateLazyScriptsForCompartment(JSContext *cx) +{ + AutoObjectVector lazyFunctions(cx); + + // Find all root lazy functions in the compartment: those which have not been + // compiled and which have a source object, indicating that their parent has + // been compiled. + for (gc::CellIter i(cx->zone(), JSFunction::FinalizeKind); !i.done(); i.next()) { + JSObject *obj = i.get(); + if (obj->compartment() == cx->compartment() && obj->isFunction()) { + JSFunction *fun = obj->toFunction(); + if (fun->isInterpretedLazy()) { + LazyScript *lazy = fun->lazyScript(); + if (lazy->sourceObject() && !lazy->maybeScript()) { + if (!lazyFunctions.append(fun)) + return false; + } + } + } + } + + // Create scripts for each lazy function, updating the list of functions to + // process with any newly exposed inner functions in created scripts. + // A function cannot be delazified until its outer script exists. + for (size_t i = 0; i < lazyFunctions.length(); i++) { + JSFunction *fun = lazyFunctions[i]->toFunction(); + + // lazyFunctions may have been populated with multiple functions for + // a lazy script. + if (!fun->isInterpretedLazy()) + continue; + + JSScript *script = fun->getOrCreateScript(cx); + if (!script) + return false; + if (!AddInnerLazyFunctionsFromScript(script, lazyFunctions)) + return false; + } + + // Repoint any clones of the original functions to their new script. + for (gc::CellIter i(cx->zone(), JSFunction::FinalizeKind); !i.done(); i.next()) { + JSObject *obj = i.get(); + if (obj->compartment() == cx->compartment() && obj->isFunction()) { + JSFunction *fun = obj->toFunction(); + if (fun->isInterpretedLazy()) { + JS_ASSERT(fun->lazyScript()->maybeScript()); + JS_ALWAYS_TRUE(fun->getOrCreateScript(cx)); + } + } + } + + return true; +} + bool JSCompartment::setDebugModeFromC(JSContext *cx, bool b, AutoDebugModeGC &dmgc) { @@ -626,6 +697,8 @@ JSCompartment::setDebugModeFromC(JSContext *cx, bool b, AutoDebugModeGC &dmgc) JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_DEBUG_NOT_IDLE); return false; } + if (enabledAfter && !CreateLazyScriptsForCompartment(cx)) + return false; } debugModeBits = (debugModeBits & ~unsigned(DebugFromC)) | (b ? DebugFromC : 0); @@ -677,10 +750,14 @@ JSCompartment::addDebuggee(JSContext *cx, js::GlobalObject *global) bool JSCompartment::addDebuggee(JSContext *cx, - js::GlobalObject *global, + GlobalObject *globalArg, AutoDebugModeGC &dmgc) { + Rooted global(cx, globalArg); + bool wasEnabled = debugMode(); + if (!wasEnabled && !CreateLazyScriptsForCompartment(cx)) + return false; if (!debuggees.put(global)) { js_ReportOutOfMemory(cx); return false; diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index aa763956641e..b88955aad9dd 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -350,9 +350,11 @@ js::XDRInterpretedFunction(XDRState *xdr, HandleObject enclosingScope, Han return false; } firstword = !!fun->atom(); - flagsword = (fun->nargs << 16) | fun->flags; + script = fun->getOrCreateScript(cx); + if (!script) + return false; atom = fun->atom(); - script = fun->nonLazyScript(); + flagsword = (fun->nargs << 16) | fun->flags; } else { fun = NewFunction(cx, NullPtr(), NULL, 0, JSFunction::INTERPRETED, NullPtr(), NullPtr(), JSFunction::FinalizeKind, TenuredObject); @@ -1057,9 +1059,10 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti if (cx->zone()->needsBarrier()) LazyScript::writeBarrierPre(lazy); + fun->flags &= ~INTERPRETED_LAZY; + fun->flags |= INTERPRETED; + if (JSScript *script = lazy->maybeScript()) { - fun->flags &= ~INTERPRETED_LAZY; - fun->flags |= INTERPRETED; fun->initScript(script); /* @@ -1072,10 +1075,9 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti return true; } - /* Lazily parsed script. */ - const jschar *chars = lazy->source()->chars(cx); - if (!chars) - return false; + fun->initScript(NULL); + + JS_ASSERT(lazy->source()->hasSourceData()); /* * GC must be suppressed for the remainder of the lazy parse, as any @@ -1083,9 +1085,10 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti */ AutoSuppressGC suppressGC(cx); - fun->flags &= ~INTERPRETED_LAZY; - fun->flags |= INTERPRETED; - fun->initScript(NULL); + /* Lazily parsed script. */ + const jschar *chars = lazy->source()->chars(cx); + if (!chars) + return false; const jschar *lazyStart = chars + lazy->begin(); size_t lazyLength = lazy->end() - lazy->begin(); diff --git a/js/src/jsfun.h b/js/src/jsfun.h index c93557a90ea8..e5d060a0e831 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -142,7 +142,6 @@ class JSFunction : public JSObject // Can be called multiple times by the parser. void setArgCount(uint16_t nargs) { - JS_ASSERT(this->nargs == 0 || this->nargs == nargs); this->nargs = nargs; } @@ -186,13 +185,6 @@ class JSFunction : public JSObject flags |= EXPR_CLOSURE; } - void markNotLazy() { - JS_ASSERT(isInterpretedLazy()); - JS_ASSERT(hasScript()); - flags |= INTERPRETED; - flags &= ~INTERPRETED_LAZY; - } - JSAtom *atom() const { return hasGuessedAtom() ? NULL : atom_.get(); } js::PropertyName *name() const { return hasGuessedAtom() || !atom_ ? NULL : atom_->asPropertyName(); } inline void initAtom(JSAtom *atom); @@ -221,7 +213,6 @@ class JSFunction : public JSObject JS_ASSERT(cx); if (isInterpretedLazy()) { JS::RootedFunction self(cx, this); - js::MaybeCheckStackRoots(cx); if (!createScriptForLazilyInterpretedFunction(cx, self)) return NULL; JS_ASSERT(self->hasScript()); diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index bb92eedcd3df..3b1e1e6e6d08 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -168,7 +168,8 @@ static const AllocKind FinalizePhaseStrings[] = { }; static const AllocKind FinalizePhaseScripts[] = { - FINALIZE_SCRIPT + FINALIZE_SCRIPT, + FINALIZE_LAZY_SCRIPT }; static const AllocKind FinalizePhaseIonCode[] = { @@ -213,7 +214,6 @@ static const AllocKind BackgroundPhaseStrings[] = { }; static const AllocKind BackgroundPhaseShapes[] = { - FINALIZE_LAZY_SCRIPT, FINALIZE_SHAPE, FINALIZE_BASE_SHAPE, FINALIZE_TYPE_OBJECT @@ -1440,7 +1440,7 @@ ArenaLists::queueScriptsForSweep(FreeOp *fop) { gcstats::AutoPhase ap(fop->runtime()->gcStats, gcstats::PHASE_SWEEP_SCRIPT); queueForForegroundSweep(fop, FINALIZE_SCRIPT); - queueForBackgroundSweep(fop, FINALIZE_LAZY_SCRIPT); + queueForForegroundSweep(fop, FINALIZE_LAZY_SCRIPT); } void diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 4eec8386f750..8eb84af8de3f 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -204,7 +204,7 @@ IsBackgroundFinalized(AllocKind kind) false, /* FINALIZE_OBJECT16 */ true, /* FINALIZE_OBJECT16_BACKGROUND */ false, /* FINALIZE_SCRIPT */ - true, /* FINALIZE_LAZY_SCRIPT */ + false, /* FINALIZE_LAZY_SCRIPT */ true, /* FINALIZE_SHAPE */ true, /* FINALIZE_BASE_SHAPE */ true, /* FINALIZE_TYPE_OBJECT */ diff --git a/js/src/jsinferinlines.h b/js/src/jsinferinlines.h index 80a74ecd756e..63bcbcd71344 100644 --- a/js/src/jsinferinlines.h +++ b/js/src/jsinferinlines.h @@ -734,28 +734,20 @@ UseNewTypeForClone(JSFunction *fun) * instance a singleton type and clone the underlying script. */ - JSScript *script = fun->nonLazyScript(); - - if (script->length >= 50) - return false; - - if (script->hasConsts() || script->hasObjects() || script->hasRegexps() || fun->isHeavyweight()) - return false; - - bool hasArguments = false; - bool hasApply = false; - - for (jsbytecode *pc = script->code; - pc != script->code + script->length; - pc += GetBytecodeLength(pc)) - { - if (*pc == JSOP_ARGUMENTS) - hasArguments = true; - if (*pc == JSOP_FUNAPPLY) - hasApply = true; + uint32_t begin, end; + if (fun->hasScript()) { + if (!fun->nonLazyScript()->usesArgumentsAndApply) + return false; + begin = fun->nonLazyScript()->sourceStart; + end = fun->nonLazyScript()->sourceEnd; + } else { + if (!fun->lazyScript()->usesArgumentsAndApply()) + return false; + begin = fun->lazyScript()->begin(); + end = fun->lazyScript()->end(); } - return hasArguments && hasApply; + return end - begin <= 100; } ///////////////////////////////////////////////////////////////////// diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index eb777511d0bb..fee7a6a1e76e 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -666,7 +666,10 @@ js::XDRScript(XDRState *xdr, HandleObject enclosingScope, HandleScript enc /* Code the nested function's enclosing scope. */ uint32_t funEnclosingScopeIndex = 0; if (mode == XDR_ENCODE) { - RootedObject staticScope(cx, (*objp)->toFunction()->nonLazyScript()->enclosingStaticScope()); + JSScript *innerScript = (*objp)->toFunction()->getOrCreateScript(cx); + if (!innerScript) + return false; + RootedObject staticScope(cx, innerScript->enclosingStaticScope()); StaticScopeIter ssi(cx, staticScope); if (ssi.done() || ssi.type() == StaticScopeIter::FUNCTION) { JS_ASSERT(ssi.done() == !fun); @@ -1226,16 +1229,13 @@ SourceDataCache::purge() const jschar * ScriptSource::chars(JSContext *cx) { -#ifdef USE_ZLIB - Rooted cached(cx, NULL); -#endif #ifdef JS_THREADSAFE if (!ready()) return cx->runtime()->sourceCompressorThread.currentChars(); #endif #ifdef USE_ZLIB if (compressed()) { - cached = cx->runtime()->sourceDataCache.lookup(this); + JSStableString *cached = cx->runtime()->sourceDataCache.lookup(this); if (!cached) { const size_t nbytes = sizeof(jschar) * (length_ + 1); jschar *decompressed = static_cast(cx->malloc_(nbytes)); @@ -1257,10 +1257,8 @@ ScriptSource::chars(JSContext *cx) } return cached->chars().get(); } - return data.source; -#else - return data.source; #endif + return data.source; } JSStableString * @@ -2324,8 +2322,11 @@ js::CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun, assertSameCompartment(cx, innerFun); clone = innerFun; } else { - if (!innerFun->getOrCreateScript(cx)) - return NULL; + if (innerFun->isInterpretedLazy()) { + AutoCompartment ac(cx, innerFun); + if (!innerFun->getOrCreateScript(cx)) + return NULL; + } RootedObject staticScope(cx, innerFun->nonLazyScript()->enclosingStaticScope()); StaticScopeIter ssi(cx, staticScope); RootedObject enclosingScope(cx); @@ -2771,11 +2772,14 @@ JSScript::markChildren(JSTracer *trc) void LazyScript::markChildren(JSTracer *trc) { - if (parent_) - MarkScriptUnbarriered(trc, &parent_, "lazyScriptParent"); + if (sourceObject_) + MarkObject(trc, &sourceObject_, "sourceObject"); + + if (parentFunction_) + MarkObject(trc, &parentFunction_, "parentFunction"); if (script_) - MarkScriptUnbarriered(trc, &script_, "lazyScript"); + MarkScript(trc, &script_, "realScript"); HeapPtrAtom *freeVariables = this->freeVariables(); for (size_t i = 0; i < numFreeVariables(); i++) @@ -2791,6 +2795,9 @@ LazyScript::finalize(FreeOp *fop) { if (table_) fop->free_(table_); + + if (originPrincipals_) + JS_DropPrincipals(fop->runtime(), originPrincipals_); } void @@ -2939,8 +2946,58 @@ JSScript::formalLivesInArgumentsObject(unsigned argSlot) return argsObjAliasesFormals() && !formalIsAliased(argSlot); } +LazyScript::LazyScript(void *table, uint32_t numFreeVariables, uint32_t numInnerFunctions, + JSVersion version, uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column) + : script_(NULL), + parentFunction_(NULL), + sourceObject_(NULL), + table_(table), + originPrincipals_(NULL), + version_(version), + numFreeVariables_(numFreeVariables), + numInnerFunctions_(numInnerFunctions), + strict_(false), + bindingsAccessedDynamically_(false), + hasDebuggerStatement_(false), + directlyInsideEval_(false), + usesArgumentsAndApply_(false), + hasBeenCloned_(false), + begin_(begin), + end_(end), + lineno_(lineno), + column_(column) +{ + JS_ASSERT(this->version() == version); + JS_ASSERT(begin <= end); +} + +void +LazyScript::initScript(JSScript *script) +{ + JS_ASSERT(script && !script_); + script_ = script; +} + +void +LazyScript::setParent(JSFunction *parentFunction, ScriptSourceObject *sourceObject, + JSPrincipals *originPrincipals) +{ + JS_ASSERT(sourceObject && !sourceObject_ && !parentFunction_ && !originPrincipals_); + parentFunction_ = parentFunction; + sourceObject_ = sourceObject; + originPrincipals_ = originPrincipals; + if (originPrincipals) + JS_HoldPrincipals(originPrincipals); +} + +ScriptSourceObject * +LazyScript::sourceObject() const +{ + return sourceObject_ ? &sourceObject_->asScriptSource() : NULL; +} + /* static */ LazyScript * -LazyScript::Create(JSContext *cx, uint32_t numFreeVariables, uint32_t numInnerFunctions, +LazyScript::Create(JSContext *cx, uint32_t numFreeVariables, uint32_t numInnerFunctions, JSVersion version, uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column) { JS_ASSERT(begin <= end); @@ -2959,7 +3016,13 @@ LazyScript::Create(JSContext *cx, uint32_t numFreeVariables, uint32_t numInnerFu if (!res) return NULL; - return new (res) LazyScript(table, numFreeVariables, numInnerFunctions, begin, end, lineno, column); + return new (res) LazyScript(table, numFreeVariables, numInnerFunctions, version, + begin, end, lineno, column); +} + +uint32_t LazyScript::staticLevel() const +{ + return parentFunction() ? parentFunction()->nonLazyScript()->staticLevel + 1 : 1; } void diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 173ba4c93a93..82b3232fd2e8 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -538,9 +538,12 @@ class JSScript : public js::gc::Cell bool isActiveEval:1; /* script came from eval(), and is still active */ bool isCachedEval:1; /* script came from eval(), and is in eval cache */ - /* Set for functions defined at the top level within an 'eval' script. */ + // Set for functions defined at the top level within an 'eval' script. bool directlyInsideEval:1; + // Both 'arguments' and f.apply() are used. This is likely to be a wrapper. + bool usesArgumentsAndApply:1; + /* script is attempted to be cloned anew at each callsite. This is temporarily needed for ParallelArray selfhosted code until type information can be made context sensitive. See discussion in @@ -1099,19 +1102,20 @@ class AliasedFormalIter struct SourceCompressionToken; - // Information about a script which may be (or has been) lazily compiled to // bytecode from its source. class LazyScript : public js::gc::Cell { - // Immediate parent in which the script is nested, or NULL if the parent - // has not been compiled yet. Lazy scripts are always functions within a - // global or eval script so there will be a parent. - JSScript *parent_; - // If non-NULL, the script has been compiled and this is a forwarding // pointer to the result. - JSScript *script_; + HeapPtrScript script_; + + // Immediate parent in which the script is nested, or NULL. + HeapPtrFunction parentFunction_; + + // Source code object, or NULL if the script in which this is nested has + // not been compiled yet. + HeapPtrObject sourceObject_; // Heap allocated table with any free variables or inner functions. void *table_; @@ -1120,14 +1124,20 @@ class LazyScript : public js::gc::Cell uint32_t padding; #endif - uint32_t numFreeVariables_; + // Assorted bits that should really be in ScriptSourceObject. + JSPrincipals *originPrincipals_; + uint32_t version_ : 8; + + uint32_t numFreeVariables_ : 24; uint32_t numInnerFunctions_ : 26; - bool strict_ : 1; - bool bindingsAccessedDynamically_ : 1; - bool hasDebuggerStatement_ : 1; - bool directlyInsideEval_:1; - bool hasBeenCloned_:1; + // N.B. These are booleans but need to be uint32_t to pack correctly on MSVC. + uint32_t strict_ : 1; + uint32_t bindingsAccessedDynamically_ : 1; + uint32_t hasDebuggerStatement_ : 1; + uint32_t directlyInsideEval_:1; + uint32_t usesArgumentsAndApply_:1; + uint32_t hasBeenCloned_:1; // Source location for the script. uint32_t begin_; @@ -1135,46 +1145,33 @@ class LazyScript : public js::gc::Cell uint32_t lineno_; uint32_t column_; - LazyScript(void *table, uint32_t numFreeVariables, uint32_t numInnerFunctions, - uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column) - : parent_(NULL), - script_(NULL), - table_(table), - numFreeVariables_(numFreeVariables), - numInnerFunctions_(numInnerFunctions), - strict_(false), - bindingsAccessedDynamically_(false), - hasDebuggerStatement_(false), - directlyInsideEval_(false), - hasBeenCloned_(false), - begin_(begin), - end_(end), - lineno_(lineno), - column_(column) - { - JS_ASSERT(begin <= end); - } + LazyScript(void *table, uint32_t numFreeVariables, uint32_t numInnerFunctions, JSVersion version, + uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column); public: static LazyScript *Create(JSContext *cx, uint32_t numFreeVariables, uint32_t numInnerFunctions, - uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column); + JSVersion version, uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column); - void initParent(JSScript *parent) { - JS_ASSERT(parent && !parent_); - parent_ = parent; - } - JSScript *parent() const { - return parent_; - } - - void initScript(JSScript *script) { - JS_ASSERT(script && !script_); - script_ = script; - } + void initScript(JSScript *script); JSScript *maybeScript() { return script_; } + JSFunction *parentFunction() const { + return parentFunction_; + } + ScriptSourceObject *sourceObject() const; + JSPrincipals *originPrincipals() const { + return originPrincipals_; + } + JSVersion version() const { + JS_STATIC_ASSERT(JSVERSION_UNKNOWN == -1); + return (version_ == JS_BIT(8) - 1) ? JSVERSION_UNKNOWN : JSVersion(version_); + } + + void setParent(JSFunction *parentFunction, ScriptSourceObject *sourceObject, + JSPrincipals *originPrincipals); + uint32_t numFreeVariables() const { return numFreeVariables_; } @@ -1217,6 +1214,13 @@ class LazyScript : public js::gc::Cell directlyInsideEval_ = true; } + bool usesArgumentsAndApply() const { + return usesArgumentsAndApply_; + } + void setUsesArgumentsAndApply() { + usesArgumentsAndApply_ = true; + } + bool hasBeenCloned() const { return hasBeenCloned_; } @@ -1225,7 +1229,7 @@ class LazyScript : public js::gc::Cell } ScriptSource *source() const { - return parent()->scriptSource(); + return sourceObject()->source(); } uint32_t begin() const { return begin_; @@ -1240,6 +1244,8 @@ class LazyScript : public js::gc::Cell return column_; } + uint32_t staticLevel() const; + Zone *zone() const { return Cell::tenuredZone(); } diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index fd14b3bba038..4f239c077a39 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -229,7 +229,6 @@ class Debugger::FrameRange } }; - /*** Breakpoints *********************************************************************************/ BreakpointSite::BreakpointSite(JSScript *script, jsbytecode *pc) @@ -686,7 +685,6 @@ Debugger::wrapDebuggeeValue(JSContext *cx, MutableHandleValue vp) assertSameCompartment(cx, object.get()); if (vp.isObject()) { - // Do we need this RootedObject? RootedObject obj(cx, &vp.toObject()); ObjectWeakMap::AddPtr p = objects.lookupForAdd(obj); @@ -2887,16 +2885,6 @@ DebuggerScript_getSourceMapUrl(JSContext *cx, unsigned argc, Value *vp) return true; } -static bool -EnsureFunctionHasScript(JSContext *cx, JSFunction *fun) -{ - if (fun->isInterpretedLazy()) { - AutoCompartment ac(cx, fun); - return fun->getOrCreateScript(cx); - } - return true; -} - static JSBool DebuggerScript_getChildScripts(JSContext *cx, unsigned argc, Value *vp) { @@ -2921,10 +2909,6 @@ DebuggerScript_getChildScripts(JSContext *cx, unsigned argc, Value *vp) obj = objects->vector[i]; if (obj->isFunction()) { fun = static_cast(obj.get()); - - if (!EnsureFunctionHasScript(cx, fun)) - return false; - funScript = fun->nonLazyScript(); s = dbg->wrapScript(cx, funScript); if (!s || !js_NewbornArrayPush(cx, result, ObjectValue(*s))) @@ -4473,9 +4457,6 @@ DebuggerObject_getParameterNames(JSContext *cx, unsigned argc, Value *vp) result->ensureDenseInitializedLength(cx, 0, fun->nargs); if (fun->isInterpreted()) { - if (!EnsureFunctionHasScript(cx, fun)) - return false; - JS_ASSERT(fun->nargs == fun->nonLazyScript()->bindings.numArgs()); if (fun->nargs > 0) { @@ -4517,9 +4498,6 @@ DebuggerObject_getScript(JSContext *cx, unsigned argc, Value *vp) return true; } - if (!EnsureFunctionHasScript(cx, fun)) - return false; - RootedScript script(cx, fun->nonLazyScript()); RootedObject scriptObject(cx, dbg->wrapScript(cx, script)); if (!scriptObject) From bdb61b948ee7f58b8afafbc92ea7b613c82a96c4 Mon Sep 17 00:00:00 2001 From: Julian Seward Date: Fri, 14 Jun 2013 14:03:25 +0200 Subject: [PATCH 11/84] Bug 882903 - SPS breadkpad unwinder segfaults with on-demand decompression on. r=glandium. --- mozglue/linker/ElfLoader.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/mozglue/linker/ElfLoader.cpp b/mozglue/linker/ElfLoader.cpp index a9a6c6a125b9..955eacb42dca 100644 --- a/mozglue/linker/ElfLoader.cpp +++ b/mozglue/linker/ElfLoader.cpp @@ -208,7 +208,14 @@ LibHandle::MappableMMap(void *addr, size_t length, off_t offset) const { MOZ_ASSERT(mappable == NULL, "MappableMMap must be called after" " GetMappableLength"); - return mappable->mmap(addr, length, PROT_READ, MAP_PRIVATE, offset); + void* mapped = mappable->mmap(addr, length, PROT_READ, MAP_PRIVATE, offset); + if (mapped != MAP_FAILED) { + /* Ensure the availability of all pages within the mapping */ + for (size_t off = 0; off < length; off += PAGE_SIZE) { + mappable->ensure(reinterpret_cast(mapped) + off); + } + } + return mapped; } void From 561a2574934086d635f0930db56a75c617e48b8d Mon Sep 17 00:00:00 2001 From: Frederik Braun Date: Wed, 15 May 2013 11:30:43 +0200 Subject: [PATCH 12/84] Bug 879316 - Clean up CSP logging code. r=imelven --- ...browser_webconsole_bug_770099_violation.js | 2 +- content/base/src/CSPUtils.jsm | 56 ++++++------------- content/base/src/contentSecurityPolicy.js | 15 +++-- 3 files changed, 28 insertions(+), 45 deletions(-) diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_770099_violation.js b/browser/devtools/webconsole/test/browser_webconsole_bug_770099_violation.js index 42524a7c1909..893401be63a3 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_770099_violation.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_770099_violation.js @@ -8,7 +8,7 @@ // Tests that the Web Console CSP messages are displayed const TEST_VIOLATION = "https://example.com/browser/browser/devtools/webconsole/test/test_bug_770099_violation.html"; -const CSP_VIOLATION_MSG = "CSP WARN: Directive default-src https://example.com:443 violated by http://some.example.com/test.png" +const CSP_VIOLATION_MSG = "Content Security Policy: Directive default-src https://example.com:443 violated by http://some.example.com/test.png" let hud = undefined; diff --git a/content/base/src/CSPUtils.jsm b/content/base/src/CSPUtils.jsm index dcc3afb5c112..9d17d5de7bdb 100644 --- a/content/base/src/CSPUtils.jsm +++ b/content/base/src/CSPUtils.jsm @@ -13,6 +13,9 @@ const Cu = Components.utils; const Ci = Components.interfaces; +const WARN_FLAG = Ci.nsIScriptError.warningFlag; +const ERROR_FLAG = Ci.nsIScriptError.ERROR_FLAG; + Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); @@ -842,7 +845,7 @@ CSPRep.prototype = { // However, our original CSP implementation required a default src // or an allow directive. if (!defaultSrcDir && !this._specCompliant) { - this.warn(CSPLocalizer.getStr("allowOrDefaultSrcRequired")); + this.log(WARN_FLAG, CSPLocalizer.getStr("allowOrDefaultSrcRequired")); return false; } @@ -888,7 +891,9 @@ CSPRep.prototype = { }, /** - * Sends a warning message to the error console and web developer console. + * Sends a message to the error console and web developer console. + * @param aFlag + * The nsIScriptError flag constant indicating severity * @param aMsg * The message to send * @param aSource (optional) @@ -898,50 +903,25 @@ CSPRep.prototype = { * @param aLineNum (optional) * The number of the line where the error occurred */ - warn: - function cspd_warn(aMsg, aSource, aScriptLine, aLineNum) { - var textMessage = 'CSP WARN: ' + aMsg + "\n"; - + log: + function cspd_log(aFlag, aMsg, aSource, aScriptLine, aLineNum) { + var textMessage = "Content Security Policy: " + aMsg; var consoleMsg = Components.classes["@mozilla.org/scripterror;1"] .createInstance(Ci.nsIScriptError); if (this._innerWindowID) { consoleMsg.initWithWindowID(textMessage, aSource, aScriptLine, aLineNum, - 0, Ci.nsIScriptError.warningFlag, - "Content Security Policy", + 0, aFlag, + "CSP", this._innerWindowID); } else { consoleMsg.init(textMessage, aSource, aScriptLine, aLineNum, 0, - Ci.nsIScriptError.warningFlag, - "Content Security Policy"); + aFlag, + "CSP"); } Components.classes["@mozilla.org/consoleservice;1"] .getService(Ci.nsIConsoleService).logMessage(consoleMsg); }, - /** - * Sends an error message to the error console and web developer console. - * @param aMsg - * The message to send - */ - error: - function cspsd_error(aMsg) { - var textMessage = 'CSP ERROR: ' + aMsg + "\n"; - - var consoleMsg = Components.classes["@mozilla.org/scripterror;1"] - .createInstance(Ci.nsIScriptError); - if (this._innerWindowID) { - consoleMsg.initWithWindowID(textMessage, null, null, 0, 0, - Ci.nsIScriptError.errorFlag, - "Content Security Policy", - this._innerWindowID); - } - else { - consoleMsg.init(textMessage, null, null, 0, 0, - Ci.nsIScriptError.errorFlag, "Content Security Policy"); - } - Components.classes["@mozilla.org/consoleservice;1"] - .getService(Ci.nsIConsoleService).logMessage(consoleMsg); - }, }; ////////////////////////////////////////////////////////////////////// @@ -1967,17 +1947,17 @@ function innerWindowFromRequest(docRequest) { function cspError(aCSPRep, aMessage) { if (aCSPRep) { - aCSPRep.error(aMessage); + aCSPRep.log(ERROR_FLAG, aMessage); } else { - (new CSPRep()).error(aMessage); + (new CSPRep()).log(ERROR_FLAG, aMessage); } } function cspWarn(aCSPRep, aMessage) { if (aCSPRep) { - aCSPRep.warn(aMessage); + aCSPRep.log(WARN_FLAG, aMessage); } else { - (new CSPRep()).warn(aMessage); + (new CSPRep()).log(WARN_FLAG, aMessage); } } diff --git a/content/base/src/contentSecurityPolicy.js b/content/base/src/contentSecurityPolicy.js index f3054742edc1..400d408aeabc 100644 --- a/content/base/src/contentSecurityPolicy.js +++ b/content/base/src/contentSecurityPolicy.js @@ -25,6 +25,9 @@ const CSP_VIOLATION_TOPIC = "csp-on-violate-policy"; const CSP_TYPE_XMLHTTPREQUEST_SPEC_COMPLIANT = "csp_type_xmlhttprequest_spec_compliant"; const CSP_TYPE_WEBSOCKET_SPEC_COMPLIANT = "csp_type_websocket_spec_compliant"; +const WARN_FLAG = Ci.nsIScriptError.warningFlag; +const ERROR_FLAG = Ci.nsIScriptError.ERROR_FLAG; + Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/CSPUtils.jsm"); @@ -180,13 +183,13 @@ ContentSecurityPolicy.prototype = { break; case Ci.nsIContentSecurityPolicy.VIOLATION_TYPE_INLINE_SCRIPT: if (!this._policy.allowsInlineScripts) - this._asyncReportViolation('self',null,'inline script base restriction', + this._asyncReportViolation('self', null, 'inline script base restriction', 'violated base restriction: Inline Scripts will not execute', aSourceFile, aScriptSample, aLineNum); break; case Ci.nsIContentSecurityPolicy.VIOLATION_TYPE_EVAL: if (!this._policy.allowsEvalInScripts) - this._asyncReportViolation('self',null,'eval script base restriction', + this._asyncReportViolation('self', null, 'eval script base restriction', 'violated base restriction: Code will not be created from strings', aSourceFile, aScriptSample, aLineNum); break; @@ -360,7 +363,7 @@ ContentSecurityPolicy.prototype = { } else { violationMessage = CSPLocalizer.getFormatStr("directiveViolated", [violatedDirective]); } - this._policy.warn(violationMessage, + this._policy.log(WARN_FLAG, violationMessage, (aSourceFile) ? aSourceFile : null, (aScriptSample) ? decodeURIComponent(aScriptSample) : null, (aLineNum) ? aLineNum : null); @@ -425,8 +428,8 @@ ContentSecurityPolicy.prototype = { } catch(e) { // it's possible that the URI was invalid, just log a // warning and skip over that. - this._policy.warn(CSPLocalizer.getFormatStr("triedToSendReport", [uris[i]])); - this._policy.warn(CSPLocalizer.getFormatStr("errorWas", [e.toString()])); + this._policy.log(WARN_FLAG, CSPLocalizer.getFormatStr("triedToSendReport", [uris[i]])); + this._policy.log(WARN_FLAG, CSPLocalizer.getFormatStr("errorWas", [e.toString()])); } } } @@ -663,7 +666,7 @@ CSPReportRedirectSink.prototype = { // nsIChannelEventSink asyncOnChannelRedirect: function channel_redirect(oldChannel, newChannel, flags, callback) { - this._policy.warn(CSPLocalizer.getFormatStr("reportPostRedirect", [oldChannel.URI.asciiSpec])); + this._policy.log(WARN_FLAG, CSPLocalizer.getFormatStr("reportPostRedirect", [oldChannel.URI.asciiSpec])); // cancel the old channel so XHR failure callback happens oldChannel.cancel(Cr.NS_ERROR_ABORT); From fe47fde6abef690738bd42e65e51d8d1e12b9ee7 Mon Sep 17 00:00:00 2001 From: Rick Eyre Date: Thu, 13 Jun 2013 17:15:14 -0400 Subject: [PATCH 13/84] Bug 882817 - Fix QI implementation of HTMLTrackElement. r=bz In certain situations we were failing debug builds due to an assertion that HTMLTrackElement was not a nsIDOMNode or nsIDOMWindow when calling NS_CheckContentLoadPolicy in HTMLTrackElement::LoadResource() This patch fixes the QI of the HTMLTrackElement so that it can be queried to an nsIDOMNode correctly. --- content/html/content/src/HTMLTrackElement.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/content/html/content/src/HTMLTrackElement.cpp b/content/html/content/src/HTMLTrackElement.cpp index f848ae4e75ed..580b36f82ad5 100644 --- a/content/html/content/src/HTMLTrackElement.cpp +++ b/content/html/content/src/HTMLTrackElement.cpp @@ -94,7 +94,8 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED_4(HTMLTrackElement, nsGenericHTMLElement, NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(HTMLTrackElement) NS_INTERFACE_MAP_ENTRY(nsIDOMHTMLElement) -NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement) + NS_HTML_CONTENT_INTERFACES(nsGenericHTMLElement) +NS_ELEMENT_INTERFACE_MAP_END void HTMLTrackElement::OnChannelRedirect(nsIChannel* aChannel, From a6d854705ba39f1a4dc32f28364decbba104ba61 Mon Sep 17 00:00:00 2001 From: Kannan Vijayan Date: Fri, 14 Jun 2013 10:39:10 -0400 Subject: [PATCH 14/84] Bug 882925 - Fix ICUnaryArith_Double stub kind. r=h4writer --- js/src/ion/BaselineIC.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/src/ion/BaselineIC.h b/js/src/ion/BaselineIC.h index 8f61016075cb..128283c48601 100644 --- a/js/src/ion/BaselineIC.h +++ b/js/src/ion/BaselineIC.h @@ -2717,7 +2717,7 @@ class ICUnaryArith_Double : public ICStub friend class ICStubSpace; ICUnaryArith_Double(IonCode *stubCode) - : ICStub(UnaryArith_Int32, stubCode) + : ICStub(UnaryArith_Double, stubCode) {} public: @@ -2733,7 +2733,7 @@ class ICUnaryArith_Double : public ICStub public: Compiler(JSContext *cx, JSOp op) - : ICMultiStubCompiler(cx, ICStub::UnaryArith_Int32, op) + : ICMultiStubCompiler(cx, ICStub::UnaryArith_Double, op) {} ICStub *getStub(ICStubSpace *space) { From 42ac4f7eebc3dc020c050c0c84436dc076e6aa8f Mon Sep 17 00:00:00 2001 From: Jim Mathies Date: Fri, 14 Jun 2013 10:42:19 -0500 Subject: [PATCH 15/84] Bug 882613 - Remove reference to nsIDocShellHistory in metro front end code bug 882079 missed. r=fyan --- browser/metro/base/content/contenthandlers/Content.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/metro/base/content/contenthandlers/Content.js b/browser/metro/base/content/contenthandlers/Content.js index e7948ba921c2..53c63d184379 100644 --- a/browser/metro/base/content/contenthandlers/Content.js +++ b/browser/metro/base/content/contenthandlers/Content.js @@ -143,7 +143,7 @@ let Content = { // pages have any privilege themselves. addEventListener("click", this, false); - docShell.QueryInterface(Ci.nsIDocShellHistory).useGlobalHistory = true; + docShell.useGlobalHistory = true; }, /******************************************* From d0a02501d701dc62a420e2e08155012f06faf9f8 Mon Sep 17 00:00:00 2001 From: Timothy Nikkel Date: Fri, 14 Jun 2013 10:53:39 -0500 Subject: [PATCH 16/84] Bug 876562. Fix scrollport size calculation that didn't make a lot of sense. r=kats It was taking the min over two values that weren't in the same unit (the first in CSS pixels, the second in dev pixels). --- mobile/android/chrome/content/browser.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 15b5dc5ebbb3..e93819ad3362 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -2985,8 +2985,8 @@ Tab.prototype = { // the clamping scroll-port size. let factor = Math.min(viewportWidth / screenWidth, pageWidth / screenWidth, viewportHeight / screenHeight, pageHeight / screenHeight); - let scrollPortWidth = Math.min(screenWidth * factor, pageWidth * zoom); - let scrollPortHeight = Math.min(screenHeight * factor, pageHeight * zoom); + let scrollPortWidth = screenWidth * factor; + let scrollPortHeight = screenHeight * factor; let win = this.browser.contentWindow; win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils). From 5e21d995cc9588526b9a97756bdc849eb6612279 Mon Sep 17 00:00:00 2001 From: Peter Van der Beken Date: Wed, 5 Jun 2013 22:19:22 +0200 Subject: [PATCH 17/84] Bug 882193 - Remove nsIDocumentRegister. r=mrbkap. --- content/base/src/nsDocument.cpp | 27 --------------------- content/base/src/nsDocument.h | 5 ---- dom/interfaces/core/moz.build | 1 - dom/interfaces/core/nsIDocumentRegister.idl | 16 ------------ 4 files changed, 49 deletions(-) delete mode 100644 dom/interfaces/core/nsIDocumentRegister.idl diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 6014b96e49c6..713bd60cbaa5 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -1537,7 +1537,6 @@ NS_INTERFACE_TABLE_HEAD(nsDocument) NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMDocumentTouch) NS_INTERFACE_TABLE_ENTRY(nsDocument, nsITouchEventReceiver) NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIInlineEventHandlers) - NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDocumentRegister) NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIObserver) NS_INTERFACE_TABLE_END NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsDocument) @@ -5075,32 +5074,6 @@ nsDocument::RegisterEnabled() return sPrefValue; } -NS_IMETHODIMP -nsDocument::Register(const nsAString& aName, const JS::Value& aOptions, - JSContext* aCx, uint8_t aOptionalArgc, - jsval* aConstructor /* out param */) -{ - RootedDictionary options(aCx); - if (aOptionalArgc > 0) { - JSAutoCompartment ac(aCx, GetWrapper()); - JS::Rooted opts(aCx, aOptions); - NS_ENSURE_TRUE(JS_WrapValue(aCx, opts.address()), - NS_ERROR_UNEXPECTED); - NS_ENSURE_TRUE(options.Init(aCx, opts), - NS_ERROR_UNEXPECTED); - } - - ErrorResult rv; - JSObject* object = Register(aCx, aName, options, rv); - if (rv.Failed()) { - return rv.ErrorCode(); - } - NS_ENSURE_TRUE(object, NS_ERROR_UNEXPECTED); - - *aConstructor = OBJECT_TO_JSVAL(object); - return NS_OK; -} - JSObject* nsDocument::Register(JSContext* aCx, const nsAString& aName, const ElementRegistrationOptions& aOptions, diff --git a/content/base/src/nsDocument.h b/content/base/src/nsDocument.h index fc960561824b..293abb01254a 100644 --- a/content/base/src/nsDocument.h +++ b/content/base/src/nsDocument.h @@ -60,7 +60,6 @@ #include "nsIProgressEventSink.h" #include "nsISecurityEventSink.h" #include "nsIChannelEventSink.h" -#include "nsIDocumentRegister.h" #include "imgIRequest.h" #include "mozilla/dom/DOMImplementation.h" #include "nsIDOMTouchEvent.h" @@ -505,7 +504,6 @@ class nsDocument : public nsIDocument, public nsStubMutationObserver, public nsIDOMDocumentTouch, public nsIInlineEventHandlers, - public nsIDocumentRegister, public nsIObserver { public: @@ -796,9 +794,6 @@ public: // nsIInlineEventHandlers NS_DECL_NSIINLINEEVENTHANDLERS - // nsIDocumentRegister - NS_DECL_NSIDOCUMENTREGISTER - // nsIObserver NS_DECL_NSIOBSERVER diff --git a/dom/interfaces/core/moz.build b/dom/interfaces/core/moz.build index 1c185e57de13..10f6ed014322 100644 --- a/dom/interfaces/core/moz.build +++ b/dom/interfaces/core/moz.build @@ -25,7 +25,6 @@ XPIDL_SOURCES += [ 'nsIDOMText.idl', 'nsIDOMUserDataHandler.idl', 'nsIDOMXMLDocument.idl', - 'nsIDocumentRegister.idl', 'nsIInlineEventHandlers.idl', ] diff --git a/dom/interfaces/core/nsIDocumentRegister.idl b/dom/interfaces/core/nsIDocumentRegister.idl deleted file mode 100644 index 701eb9936ba5..000000000000 --- a/dom/interfaces/core/nsIDocumentRegister.idl +++ /dev/null @@ -1,16 +0,0 @@ -/* -*- 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/. */ - -#include "nsISupports.idl" - -[scriptable, uuid(e35935bd-ebae-4e0d-93bf-efa93ab14c05)] -interface nsIDocumentRegister : nsISupports -{ - [optional_argc, - implicit_jscontext] jsval register(in DOMString name, - [optional] in jsval options) - raises(DOMException); -}; - From 583f9d98a8963825de1650f40ac60c27c1e72bc8 Mon Sep 17 00:00:00 2001 From: Peter Van der Beken Date: Mon, 25 Mar 2013 11:36:24 +0100 Subject: [PATCH 18/84] Bug 851465 - Remove slim wrappers - stop constructing slim wrappers. r=bholley. --- dom/base/nsDOMClassInfo.cpp | 8 +- js/xpconnect/src/XPCConvert.cpp | 31 +------- js/xpconnect/src/XPCWrappedNative.cpp | 102 -------------------------- js/xpconnect/src/xpcprivate.h | 4 - xpcom/base/ErrorList.h | 7 -- 5 files changed, 4 insertions(+), 148 deletions(-) diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index dca001c3c7f3..045612ec173c 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -5099,8 +5099,7 @@ nsNodeSH::PreCreate(nsISupports *nativeObj, JSContext *cx, JSObject *aGlobalObj, nsresult rv = WrapNativeParent(cx, globalObj, native_parent, parentObj); NS_ENSURE_SUCCESS(rv, rv); - return node->ChromeOnlyAccess() ? - NS_SUCCESS_CHROME_ACCESS_ONLY : NS_SUCCESS_ALLOW_SLIM_WRAPPERS; + return node->ChromeOnlyAccess() ? NS_SUCCESS_CHROME_ACCESS_ONLY : NS_OK; } NS_IMETHODIMP @@ -5261,8 +5260,7 @@ nsElementSH::PreCreate(nsISupports *nativeObj, JSContext *cx, if (element->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) && doc->BindingManager()->GetBinding(element)) { - // Don't allow slim wrappers. - return rv == NS_SUCCESS_ALLOW_SLIM_WRAPPERS ? NS_OK : rv; + return rv; } mozilla::css::URLValue *bindingURL; @@ -5276,7 +5274,7 @@ nsElementSH::PreCreate(nsISupports *nativeObj, JSContext *cx, element->SetFlags(NODE_ATTACH_BINDING_ON_POSTCREATE); - return rv == NS_SUCCESS_ALLOW_SLIM_WRAPPERS ? NS_OK : rv; + return rv; } NS_IMETHODIMP diff --git a/js/xpconnect/src/XPCConvert.cpp b/js/xpconnect/src/XPCConvert.cpp index 4e90d835dd5c..3ed83b60deea 100644 --- a/js/xpconnect/src/XPCConvert.cpp +++ b/js/xpconnect/src/XPCConvert.cpp @@ -819,7 +819,6 @@ XPCConvert::NativeInterface2JSObject(jsval* d, // object will create (and fill the cache) from its WrapObject call. nsWrapperCache *cache = aHelper.GetWrapperCache(); - bool tryConstructSlimWrapper = false; RootedObject flat(cx); if (cache) { flat = cache->GetWrapper(); @@ -840,39 +839,11 @@ XPCConvert::NativeInterface2JSObject(jsval* d, } } - if (!dest) { - if (!flat) { - tryConstructSlimWrapper = true; - } else if (IS_SLIM_WRAPPER_OBJECT(flat)) { - if (js::IsObjectInContextCompartment(flat, cx)) { - *d = OBJECT_TO_JSVAL(flat); - return true; - } - } - } + MOZ_ASSERT_IF(flat, !IS_SLIM_WRAPPER_OBJECT(flat)); } else { flat = nullptr; } - // If we're not handing this wrapper to an nsIXPConnectJSObjectHolder, and - // the object supports slim wrappers, try to create one here. - if (tryConstructSlimWrapper) { - RootedValue slim(cx); - if (ConstructSlimWrapper(aHelper, xpcscope, &slim)) { - *d = slim; - return true; - } - - if (JS_IsExceptionPending(cx)) - return false; - - // Even if ConstructSlimWrapper returns false it might have created a - // wrapper (while calling the PreCreate hook). In that case we need to - // fall through because we either have a slim wrapper that needs to be - // morphed or an XPCWrappedNative. - flat = cache->GetWrapper(); - } - // We can't simply construct a slim wrapper. Go ahead and create an // XPCWrappedNative for this object. At this point, |flat| could be // non-null, meaning that either we already have a wrapped native from diff --git a/js/xpconnect/src/XPCWrappedNative.cpp b/js/xpconnect/src/XPCWrappedNative.cpp index cf62f09bec81..a9a39499c50d 100644 --- a/js/xpconnect/src/XPCWrappedNative.cpp +++ b/js/xpconnect/src/XPCWrappedNative.cpp @@ -3568,105 +3568,3 @@ MorphSlimWrapper(JSContext *cx, HandleObject obj) getter_AddRefs(wn)); return NS_SUCCEEDED(rv); } - -#ifdef DEBUG_slimwrappers -static uint32_t sSlimWrappers; -#endif - -JSBool -ConstructSlimWrapper(xpcObjectHelper &aHelper, - XPCWrappedNativeScope* xpcScope, MutableHandleValue rval) -{ - AutoJSContext cx; - nsISupports *identityObj = aHelper.GetCanonical(); - nsXPCClassInfo *classInfoHelper = aHelper.GetXPCClassInfo(); - - if (!classInfoHelper) { - SLIM_LOG_NOT_CREATED(cx, identityObj, "No classinfo helper"); - return false; - } - - XPCNativeScriptableFlags flags(classInfoHelper->GetScriptableFlags()); - - NS_ASSERTION(flags.DontAskInstanceForScriptable(), - "Not supported for cached wrappers!"); - - RootedObject parent(cx, xpcScope->GetGlobalJSObject()); - if (!flags.WantPreCreate()) { - SLIM_LOG_NOT_CREATED(cx, identityObj, - "scriptable helper has no PreCreate hook"); - - return false; - } - - // PreCreate may touch dead compartments. - js::AutoMaybeTouchDeadZones agc(parent); - - RootedObject plannedParent(cx, parent); - nsresult rv = classInfoHelper->PreCreate(identityObj, cx, parent, parent.address()); - if (rv != NS_SUCCESS_ALLOW_SLIM_WRAPPERS) { - SLIM_LOG_NOT_CREATED(cx, identityObj, "PreCreate hook refused"); - - return false; - } - - if (!js::IsObjectInContextCompartment(parent, cx)) { - SLIM_LOG_NOT_CREATED(cx, identityObj, "wrong compartment"); - - return false; - } - - JSAutoCompartment ac(cx, parent); - - if (parent != plannedParent) { - XPCWrappedNativeScope *newXpcScope = GetObjectScope(parent); - if (newXpcScope != xpcScope) { - SLIM_LOG_NOT_CREATED(cx, identityObj, "crossing origins"); - - return false; - } - } - - // The PreCreate hook could have forced the creation of a wrapper, need - // to check for that here and return early. - nsWrapperCache *cache = aHelper.GetWrapperCache(); - JSObject* wrapper = cache->GetWrapper(); - if (wrapper) { - rval.setObject(*wrapper); - - return true; - } - - uint32_t interfacesBitmap = classInfoHelper->GetInterfacesBitmap(); - XPCNativeScriptableCreateInfo - sciProto(aHelper.forgetXPCClassInfo(), flags, interfacesBitmap); - - AutoMarkingWrappedNativeProtoPtr xpcproto(cx); - xpcproto = XPCWrappedNativeProto::GetNewOrUsed(xpcScope, classInfoHelper, &sciProto); - if (!xpcproto) - return false; - - XPCNativeScriptableInfo* si = xpcproto->GetScriptableInfo(); - JSClass* jsclazz = si->GetSlimJSClass(); - if (!jsclazz) - return false; - - wrapper = JS_NewObject(cx, jsclazz, xpcproto->GetJSProtoObject(), parent); - if (!wrapper) - return false; - - JS_SetPrivate(wrapper, identityObj); - SetSlimWrapperProto(wrapper, xpcproto.get()); - - // Transfer ownership to the wrapper's private. - aHelper.forgetCanonical(); - - cache->SetWrapper(wrapper); - - SLIM_LOG(("+++++ %i created slim wrapper (%p, %p, %p)\n", ++sSlimWrappers, - wrapper, p, xpcScope)); - - rval.setObject(*wrapper); - - return true; -} diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 0354be0b7840..525e60e83e93 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -2241,10 +2241,6 @@ private: XPCNativeScriptableInfo* mScriptableInfo; }; -class xpcObjectHelper; -extern JSBool ConstructSlimWrapper(xpcObjectHelper &aHelper, - XPCWrappedNativeScope* xpcScope, - JS::MutableHandleValue rval); extern JSBool MorphSlimWrapper(JSContext *cx, JS::HandleObject obj); /***********************************************/ diff --git a/xpcom/base/ErrorList.h b/xpcom/base/ErrorList.h index 12e02ea419d2..7ed73da0612e 100644 --- a/xpcom/base/ErrorList.h +++ b/xpcom/base/ErrorList.h @@ -599,13 +599,6 @@ * filename begins with chrome://global/) shoudl return this from their * scriptable helper's PreCreate hook. */ ERROR(NS_SUCCESS_CHROME_ACCESS_ONLY, SUCCESS(2)), - /* Classes that want slim wrappers should return - * NS_SUCCESS_ALLOW_SLIM_WRAPPERS from their scriptable helper's PreCreate - * hook. They must also force a parent for their wrapper (from the PreCreate - * hook), they must implement nsWrapperCache and their scriptable helper must - * implement nsXPCClassInfo and must return DONT_ASK_INSTANCE_FOR_SCRIPTABLE - * in the flags. */ - ERROR(NS_SUCCESS_ALLOW_SLIM_WRAPPERS, SUCCESS(3)), #undef MODULE From a6f9979ef067fcb426f0761ddd970878d3974c8b Mon Sep 17 00:00:00 2001 From: Peter Van der Beken Date: Fri, 19 Apr 2013 21:57:15 +0200 Subject: [PATCH 19/84] Bug 851465 - Remove slim wrappers - stop morphing slim wrappers. r=bholley. --- content/base/src/nsNodeUtils.cpp | 32 +++--- js/xpconnect/src/XPCComponents.cpp | 4 - js/xpconnect/src/XPCConvert.cpp | 11 -- js/xpconnect/src/XPCJSID.cpp | 33 ++---- js/xpconnect/src/XPCWrappedNative.cpp | 128 +-------------------- js/xpconnect/src/XPCWrappedNativeJSOps.cpp | 63 +--------- js/xpconnect/src/nsXPConnect.cpp | 24 +--- js/xpconnect/src/xpcprivate.h | 29 ----- js/xpconnect/src/xpcpublic.h | 3 - js/xpconnect/wrappers/WrapperFactory.cpp | 5 - 10 files changed, 34 insertions(+), 298 deletions(-) diff --git a/content/base/src/nsNodeUtils.cpp b/content/base/src/nsNodeUtils.cpp index ba7bcd514406..15d926a034d4 100644 --- a/content/base/src/nsNodeUtils.cpp +++ b/content/base/src/nsNodeUtils.cpp @@ -401,13 +401,6 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, bool aClone, bool aDeep, AutoJSContext cx; nsresult rv; - JS::RootedObject wrapper(cx); - bool isDOMBinding; - if (aReparentScope && (wrapper = aNode->GetWrapper()) && - !(isDOMBinding = IsDOMObject(wrapper))) { - rv = xpc_MorphSlimWrapper(cx, aNode); - NS_ENSURE_SUCCESS(rv, rv); - } nsNodeInfoManager *nodeInfoManager = aNewNodeInfoManager; @@ -523,19 +516,22 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, bool aClone, bool aDeep, elem->RecompileScriptEventListeners(); } - if (aReparentScope && wrapper) { - if (isDOMBinding) { - rv = ReparentWrapper(cx, wrapper); - } else { - nsIXPConnect *xpc = nsContentUtils::XPConnect(); - if (xpc) { - rv = xpc->ReparentWrappedNativeIfFound(cx, wrapper, aReparentScope, aNode); + if (aReparentScope) { + JS::Rooted wrapper(cx); + if ((wrapper = aNode->GetWrapper())) { + if (IsDOMObject(wrapper)) { + rv = ReparentWrapper(cx, wrapper); + } else { + nsIXPConnect *xpc = nsContentUtils::XPConnect(); + if (xpc) { + rv = xpc->ReparentWrappedNativeIfFound(cx, wrapper, aReparentScope, aNode); + } } - } - if (NS_FAILED(rv)) { - aNode->mNodeInfo.swap(nodeInfo); + if (NS_FAILED(rv)) { + aNode->mNodeInfo.swap(nodeInfo); - return rv; + return rv; + } } } } diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp index c9c4b2b7525b..602f24424a56 100644 --- a/js/xpconnect/src/XPCComponents.cpp +++ b/js/xpconnect/src/XPCComponents.cpp @@ -2684,10 +2684,6 @@ nsXPCComponents_Utils::LookupMethod(const JS::Value& object, // Enter the target compartment. JSAutoCompartment ac(cx, obj); - // Morph slim wrappers. - if (IS_SLIM_WRAPPER(obj) && !MorphSlimWrapper(cx, obj)) - return NS_ERROR_FAILURE; - // Now, try to create an Xray wrapper around the object. This won't work // if the object isn't Xray-able. In that case, we throw. JSObject *xray = WrapperFactory::WrapForSameCompartmentXray(cx, obj); diff --git a/js/xpconnect/src/XPCConvert.cpp b/js/xpconnect/src/XPCConvert.cpp index 3ed83b60deea..20309e8b58b6 100644 --- a/js/xpconnect/src/XPCConvert.cpp +++ b/js/xpconnect/src/XPCConvert.cpp @@ -887,17 +887,6 @@ XPCConvert::NativeInterface2JSObject(jsval* d, wrapper->FindTearOff(iface, false, &rv); else rv = NS_OK; - } else { - NS_ASSERTION(IS_SLIM_WRAPPER(flat), - "What kind of wrapper is this?"); - - SLIM_LOG(("***** morphing from XPCConvert::NativeInterface2JSObject" - "(%p)\n", - static_cast(xpc_GetJSPrivate(flat)))); - - rv = XPCWrappedNative::Morph(flat, iface, cache, - getter_AddRefs(strongWrapper)); - wrapper = strongWrapper; } if (NS_FAILED(rv) && pErr) diff --git a/js/xpconnect/src/XPCJSID.cpp b/js/xpconnect/src/XPCJSID.cpp index 175731354f38..477eb1e9590d 100644 --- a/js/xpconnect/src/XPCJSID.cpp +++ b/js/xpconnect/src/XPCJSID.cpp @@ -505,7 +505,6 @@ nsJSIID::HasInstance(nsIXPConnectWrappedNative *wrapper, NS_ASSERTION(obj, "when is an object not an object?"); - nsISupports *identity = nullptr; // is this really a native xpcom object with a wrapper? const nsIID* iid; mInfo->GetIIDShared(&iid); @@ -514,30 +513,16 @@ nsJSIID::HasInstance(nsIXPConnectWrappedNative *wrapper, if (!obj) return NS_OK; - if (IS_SLIM_WRAPPER(obj)) { - XPCWrappedNativeProto* proto = GetSlimWrapperProto(obj); - if (proto->GetSet()->HasInterfaceWithAncestor(iid)) { - *bp = true; + if (IsDOMObject(obj)) { + // Not all DOM objects implement nsISupports. But if they don't, + // there's nothing to do in this HasInstance hook. + nsISupports *identity = UnwrapDOMObjectToISupports(obj); + if (!identity) return NS_OK; - } - -#ifdef DEBUG_slimwrappers - char foo[NSID_LENGTH]; - iid->ToProvidedString(foo); - SLIM_LOG_WILL_MORPH_FOR_PROP(cx, obj, foo); -#endif - if (!MorphSlimWrapper(cx, obj)) - return NS_ERROR_FAILURE; - } else if (IsDOMObject(obj)) { - // Not all DOM objects implement nsISupports. But if they don't, - // there's nothing to do in this HasInstance hook. - identity = UnwrapDOMObjectToISupports(obj); - if (!identity) - return NS_OK; - nsCOMPtr supp; - identity->QueryInterface(*iid, getter_AddRefs(supp)); - *bp = supp; - return NS_OK; + nsCOMPtr supp; + identity->QueryInterface(*iid, getter_AddRefs(supp)); + *bp = supp; + return NS_OK; } MOZ_ASSERT(IS_WN_WRAPPER(obj)); diff --git a/js/xpconnect/src/XPCWrappedNative.cpp b/js/xpconnect/src/XPCWrappedNative.cpp index a9a39499c50d..9d60bd2ba756 100644 --- a/js/xpconnect/src/XPCWrappedNative.cpp +++ b/js/xpconnect/src/XPCWrappedNative.cpp @@ -532,15 +532,8 @@ XPCWrappedNative::GetNewOrUsed(xpcObjectHelper& helper, if (cache) { RootedObject cached(cx, cache->GetWrapper()); - if (cached) { - if (IS_SLIM_WRAPPER_OBJECT(cached)) { - if (NS_FAILED(XPCWrappedNative::Morph(cached, - Interface, cache, getter_AddRefs(wrapper)))) - return NS_ERROR_FAILURE; - } else { - wrapper = static_cast(xpc_GetJSPrivate(cached)); - } - } + if (cached) + wrapper = static_cast(xpc_GetJSPrivate(cached)); } else { // scoped lock XPCAutoLock lock(mapLock); @@ -711,67 +704,6 @@ FinishCreate(XPCWrappedNativeScope* Scope, return NS_OK; } -// static -nsresult -XPCWrappedNative::Morph(HandleObject existingJSObject, - XPCNativeInterface* Interface, - nsWrapperCache *cache, - XPCWrappedNative** resultWrapper) -{ - AutoJSContext cx; - NS_ASSERTION(IS_SLIM_WRAPPER(existingJSObject), - "Trying to morph a JSObject that's not a slim wrapper?"); - - nsISupports *identity = - static_cast(xpc_GetJSPrivate(existingJSObject)); - XPCWrappedNativeProto *proto = GetSlimWrapperProto(existingJSObject); - -#if DEBUG - // FIXME Can't assert this until - // https://bugzilla.mozilla.org/show_bug.cgi?id=343141 is fixed. -#if 0 - if (proto->GetScriptableInfo()->GetFlags().WantPreCreate()) { - JSObject* parent = JS_GetParent(existingJSObject); - JSObject* plannedParent = parent; - nsresult rv = - proto->GetScriptableInfo()->GetCallback()->PreCreate(identity, ccx, - parent, - &parent); - if (NS_FAILED(rv)) - return rv; - - NS_ASSERTION(parent == plannedParent, - "PreCreate returned a different parent"); - } -#endif -#endif - - nsRefPtr wrapper = new XPCWrappedNative(dont_AddRef(identity), proto); - if (!wrapper) - return NS_ERROR_FAILURE; - - NS_ASSERTION(!xpc::WrapperFactory::IsXrayWrapper(js::GetObjectParent(existingJSObject)), - "Xray wrapper being used to parent XPCWrappedNative?"); - - // We use an AutoMarkingPtr here because it is possible for JS gc to happen - // after we have Init'd the wrapper but *before* we add it to the hashtable. - // This would cause the mSet to get collected and we'd later crash. I've - // *seen* this happen. - AutoMarkingWrappedNativePtr wrapperMarker(cx, wrapper); - - JSAutoCompartment ac(cx, existingJSObject); - if (!wrapper->Init(existingJSObject)) - return NS_ERROR_FAILURE; - - nsresult rv; - if (Interface && !wrapper->FindTearOff(Interface, false, &rv)) { - NS_ASSERTION(NS_FAILED(rv), "returning NS_OK on failure"); - return rv; - } - - return FinishCreate(wrapper->GetScope(), Interface, cache, wrapper, resultWrapper); -} - // static nsresult XPCWrappedNative::GetUsedOnly(nsISupports* Object, @@ -787,17 +719,11 @@ XPCWrappedNative::GetUsedOnly(nsISupports* Object, CallQueryInterface(Object, &cache); if (cache) { RootedObject flat(cx, cache->GetWrapper()); - if (flat && IS_SLIM_WRAPPER_OBJECT(flat) && !MorphSlimWrapper(cx, flat)) - return NS_ERROR_FAILURE; - - wrapper = flat ? - static_cast(xpc_GetJSPrivate(flat)) : - nullptr; - - if (!wrapper) { + if (!flat) { *resultWrapper = nullptr; return NS_OK; } + wrapper = static_cast(xpc_GetJSPrivate(flat)); NS_ADDREF(wrapper); } else { nsCOMPtr identity = do_QueryInterface(Object); @@ -1067,10 +993,6 @@ XPCWrappedNative::GatherScriptableCreateInfo(nsISupports* obj, return sciProto; } -#ifdef DEBUG_slimwrappers -static uint32_t sMorphedSlimWrappers; -#endif - JSBool XPCWrappedNative::Init(HandleObject parent, const XPCNativeScriptableCreateInfo* sci) @@ -1129,33 +1051,12 @@ XPCWrappedNative::Init(HandleObject parent, return FinishInit(); } -JSBool -XPCWrappedNative::Init(JSObject *existingJSObject) -{ - // Set up the private to point to the WN. - JS_SetPrivate(existingJSObject, this); - - // Officially mark us as non-slim. - MorphMultiSlot(existingJSObject); - - mScriptableInfo = GetProto()->GetScriptableInfo(); - mFlatJSObject = existingJSObject; - - SLIM_LOG(("----- %i morphed slim wrapper (mFlatJSObject: %p, %p)\n", - ++sMorphedSlimWrappers, mFlatJSObject, - static_cast(xpc_GetJSPrivate(mFlatJSObject)))); - - return FinishInit(); -} - JSBool XPCWrappedNative::FinishInit() { AutoJSContext cx; // For all WNs, we want to make sure that the multislot starts out as null. - // This happens explicitly when morphing a slim wrapper, but we need to - // make sure it happens in the other cases too. JS_SetReservedSlot(mFlatJSObject, WRAPPER_MULTISLOT, JSVAL_NULL); // This reference will be released when mFlatJSObject is finalized. @@ -1693,12 +1594,6 @@ RescueOrphans(HandleObject obj) } } - // Morph any slim wrappers, lest they confuse us. - if (IS_SLIM_WRAPPER(parentObj)) { - bool ok = MorphSlimWrapper(cx, parentObj); - NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); - } - // Recursively fix up orphans on the parent chain. rv = RescueOrphans(parentObj); NS_ENSURE_SUCCESS(rv, rv); @@ -3553,18 +3448,3 @@ XPCJSObjectHolder::newHolder(JSObject* obj) } return new XPCJSObjectHolder(obj); } - -JSBool -MorphSlimWrapper(JSContext *cx, HandleObject obj) -{ - SLIM_LOG(("***** morphing from MorphSlimToWrapper (%p, %p)\n", - obj, static_cast(xpc_GetJSPrivate(obj)))); - - nsISupports* object = static_cast(xpc_GetJSPrivate(obj)); - nsWrapperCache *cache = nullptr; - CallQueryInterface(object, &cache); - nsRefPtr wn; - nsresult rv = XPCWrappedNative::Morph(obj, nullptr, cache, - getter_AddRefs(wn)); - return NS_SUCCEEDED(rv); -} diff --git a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp index 5ad652d65421..4954a7aedbfd 100644 --- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp +++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp @@ -30,13 +30,6 @@ static JSBool Throw(nsresult errNum, JSContext* cx) // Handy macro used in many callback stub below. -#define MORPH_SLIM_WRAPPER(cx, obj) \ - PR_BEGIN_MACRO \ - SLIM_LOG_WILL_MORPH(cx, obj); \ - if (IS_SLIM_WRAPPER(obj) && !MorphSlimWrapper(cx, obj)) \ - return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); \ - PR_END_MACRO - #define THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper) \ PR_BEGIN_MACRO \ if (!wrapper) \ @@ -173,7 +166,6 @@ XPC_WN_DoubleWrappedGetter(JSContext *cx, unsigned argc, jsval *vp) if (!obj) return false; - MORPH_SLIM_WRAPPER(cx, obj); XPCCallContext ccx(JS_CALLER, cx, obj); XPCWrappedNative* wrapper = ccx.GetWrapper(); THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); @@ -513,7 +505,6 @@ XPC_WN_Shared_Convert(JSContext *cx, JSHandleObject obj, JSType type, JSMutableH return true; } - MORPH_SLIM_WRAPPER(cx, obj); XPCCallContext ccx(JS_CALLER, cx, obj); XPCWrappedNative* wrapper = ccx.GetWrapper(); THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); @@ -566,7 +557,6 @@ XPC_WN_Shared_Convert(JSContext *cx, JSHandleObject obj, JSType type, JSMutableH static JSBool XPC_WN_Shared_Enumerate(JSContext *cx, JSHandleObject obj) { - MORPH_SLIM_WRAPPER(cx, obj); XPCCallContext ccx(JS_CALLER, cx, obj); XPCWrappedNative* wrapper = ccx.GetWrapper(); THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); @@ -693,7 +683,6 @@ XPC_WN_NoHelper_Trace(JSTracer *trc, JSObject *obj) static JSBool XPC_WN_NoHelper_Resolve(JSContext *cx, JSHandleObject obj, JSHandleId id) { - MORPH_SLIM_WRAPPER(cx, obj); XPCCallContext ccx(JS_CALLER, cx, obj, NullPtr(), id); XPCWrappedNative* wrapper = ccx.GetWrapper(); THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); @@ -826,7 +815,6 @@ XPCWrappedNativeJSClass XPC_WN_NoHelper_JSClass = { static JSBool XPC_WN_MaybeResolvingPropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp) { - MORPH_SLIM_WRAPPER(cx, obj); XPCCallContext ccx(JS_CALLER, cx, obj); XPCWrappedNative* wrapper = ccx.GetWrapper(); THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); @@ -846,7 +834,6 @@ XPC_WN_MaybeResolvingStrictPropertyStub(JSContext *cx, JSHandleObject obj, JSHan static JSBool XPC_WN_MaybeResolvingDeletePropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool *succeeded) { - MORPH_SLIM_WRAPPER(cx, obj); XPCCallContext ccx(JS_CALLER, cx, obj); XPCWrappedNative* wrapper = ccx.GetWrapper(); THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); @@ -859,13 +846,6 @@ XPC_WN_MaybeResolvingDeletePropertyStub(JSContext *cx, JSHandleObject obj, JSHan } // macro fun! -#define PRE_HELPER_STUB_NO_SLIM \ - XPCWrappedNative* wrapper = \ - XPCWrappedNative::GetAndMorphWrappedNativeOfJSObject(cx, obj); \ - THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); \ - bool retval = true; \ - nsresult rv = wrapper->GetScriptableCallback()-> - #define PRE_HELPER_STUB \ XPCWrappedNative* wrapper; \ nsIXPCScriptable* si; \ @@ -934,8 +914,7 @@ XPC_WN_Helper_SetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBo static JSBool XPC_WN_Helper_Convert(JSContext *cx, JSHandleObject obj, JSType type, JSMutableHandleValue vp) { - SLIM_LOG_WILL_MORPH(cx, obj); - PRE_HELPER_STUB_NO_SLIM + PRE_HELPER_STUB Convert(wrapper, cx, obj, type, vp.address(), &retval); POST_HELPER_STUB } @@ -963,8 +942,7 @@ XPC_WN_Helper_Call(JSContext *cx, unsigned argc, jsval *vp) MOZ_ASSERT(obj == ccx.GetFlattenedJSObject()); - SLIM_LOG_WILL_MORPH(cx, obj); - PRE_HELPER_STUB_NO_SLIM + PRE_HELPER_STUB Call(wrapper, cx, obj, args, &retval); POST_HELPER_STUB } @@ -984,8 +962,7 @@ XPC_WN_Helper_Construct(JSContext *cx, unsigned argc, jsval *vp) MOZ_ASSERT(obj == ccx.GetFlattenedJSObject()); - SLIM_LOG_WILL_MORPH(cx, obj); - PRE_HELPER_STUB_NO_SLIM + PRE_HELPER_STUB Construct(wrapper, cx, obj, args, &retval); POST_HELPER_STUB } @@ -993,9 +970,8 @@ XPC_WN_Helper_Construct(JSContext *cx, unsigned argc, jsval *vp) static JSBool XPC_WN_Helper_HasInstance(JSContext *cx, JSHandleObject obj, JSMutableHandleValue valp, JSBool *bp) { - SLIM_LOG_WILL_MORPH(cx, obj); bool retval2; - PRE_HELPER_STUB_NO_SLIM + PRE_HELPER_STUB HasInstance(wrapper, cx, obj, valp, &retval2, &retval); *bp = retval2; POST_HELPER_STUB @@ -1158,8 +1134,6 @@ XPC_WN_JSOp_Enumerate(JSContext *cx, JSHandleObject obj, JSIterateOp enum_op, return JS_EnumerateState(cx, obj, enum_op, statep, idp); } - MORPH_SLIM_WRAPPER(cx, obj); - XPCCallContext ccx(JS_CALLER, cx, obj); XPCWrappedNative* wrapper = ccx.GetWrapper(); THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); @@ -1453,18 +1427,6 @@ XPC_WN_CallMethod(JSContext *cx, unsigned argc, jsval *vp) if (!obj) return false; -#ifdef DEBUG_slimwrappers - { - JSFunction* fun = funobj->getFunctionPrivate(); - JSString *funid = JS_GetFunctionDisplayId(fun); - JSAutoByteString bytes; - const char *funname = !funid ? "" : bytes.encodeLatin1(cx, funid) ? bytes.ptr() : ""; - SLIM_LOG_WILL_MORPH_FOR_PROP(cx, obj, funname); - } -#endif - if (IS_SLIM_WRAPPER(obj) && !MorphSlimWrapper(cx, obj)) - return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); - obj = FixUpThisIfBroken(obj, funobj); XPCCallContext ccx(JS_CALLER, cx, obj, funobj, JSID_VOIDHANDLE, argc, JS_ARGV(cx, vp), vp); @@ -1490,21 +1452,6 @@ XPC_WN_GetterSetter(JSContext *cx, unsigned argc, jsval *vp) if (!obj) return false; -#ifdef DEBUG_slimwrappers - { - const char* funname = nullptr; - JSAutoByteString bytes; - if (JS_TypeOfValue(cx, JS_CALLEE(cx, vp)) == JSTYPE_FUNCTION) { - JSString *funid = JS_GetFunctionDisplayId(funobj->getFunctionPrivate()); - funname = !funid ? "" : bytes.encodeLatin1(cx, funid) ? bytes.ptr() : ""; - } - SLIM_LOG_WILL_MORPH_FOR_PROP(cx, obj, funname); - } -#endif - if (IS_SLIM_WRAPPER(obj) && !MorphSlimWrapper(cx, obj)) - return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); - - obj = FixUpThisIfBroken(obj, funobj); XPCCallContext ccx(JS_CALLER, cx, obj, funobj, JSID_VOIDHANDLE, argc, JS_ARGV(cx, vp), vp); @@ -1787,7 +1734,6 @@ js::Class XPC_WN_NoMods_NoCall_Proto_JSClass = { static JSBool XPC_WN_TearOff_Enumerate(JSContext *cx, JSHandleObject obj) { - MORPH_SLIM_WRAPPER(cx, obj); XPCCallContext ccx(JS_CALLER, cx, obj); XPCWrappedNative* wrapper = ccx.GetWrapper(); THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); @@ -1810,7 +1756,6 @@ XPC_WN_TearOff_Enumerate(JSContext *cx, JSHandleObject obj) static JSBool XPC_WN_TearOff_Resolve(JSContext *cx, JSHandleObject obj, JSHandleId id) { - MORPH_SLIM_WRAPPER(cx, obj); XPCCallContext ccx(JS_CALLER, cx, obj); XPCWrappedNative* wrapper = ccx.GetWrapper(); THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index ecbf68b9185c..1d48c27d7807 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -1080,21 +1080,6 @@ nsXPConnect::InitClassesWithNewWrappedGlobal(JSContext * aJSContext, return NS_OK; } -nsresult -xpc_MorphSlimWrapper(JSContext *cx, nsISupports *tomorph) -{ - nsWrapperCache *cache; - CallQueryInterface(tomorph, &cache); - if (!cache) - return NS_OK; - - RootedObject obj(cx, cache->GetWrapper()); - if (!obj || !IS_SLIM_WRAPPER(obj)) - return NS_OK; - NS_ENSURE_STATE(MorphSlimWrapper(cx, obj)); - return NS_OK; -} - static nsresult NativeInterface2JSObject(HandleObject aScope, nsISupports *aCOMObj, @@ -1236,12 +1221,9 @@ nsXPConnect::GetWrappedNativeOfJSObject(JSContext * aJSContext, NS_ASSERTION(_retval, "bad param"); RootedObject aJSObj(aJSContext, aJSObjArg); - SLIM_LOG_WILL_MORPH(aJSContext, aJSObj); - nsIXPConnectWrappedNative* wrapper = - XPCWrappedNative::GetAndMorphWrappedNativeOfJSObject(aJSContext, aJSObj); - if (wrapper) { - NS_ADDREF(wrapper); - *_retval = wrapper; + aJSObj = js::CheckedUnwrap(aJSObj, /* stopAtOuter = */ false); + if (aJSObj && IS_WN_WRAPPER(aJSObj)) { + NS_IF_ADDREF(*_retval = XPCWrappedNative::Get(aJSObj)); return NS_OK; } diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 525e60e83e93..83d9068d0781 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -304,16 +304,6 @@ inline XPCWrappedNativeProto* GetSlimWrapperProto(JSObject *obj) return static_cast(v.toPrivate()); } -// A slim wrapper is identified by having a native pointer in its reserved slot. -// This function, therefore, does the official transition from a slim wrapper to -// a non-slim wrapper. -inline void MorphMultiSlot(JSObject *obj) -{ - MOZ_ASSERT(IS_SLIM_WRAPPER(obj)); - JS_SetReservedSlot(obj, WRAPPER_MULTISLOT, JSVAL_NULL); - MOZ_ASSERT(!IS_SLIM_WRAPPER(obj)); -} - inline void SetWNExpandoChain(JSObject *obj, JSObject *chain) { MOZ_ASSERT(IS_WN_WRAPPER(obj)); @@ -2241,8 +2231,6 @@ private: XPCNativeScriptableInfo* mScriptableInfo; }; -extern JSBool MorphSlimWrapper(JSContext *cx, JS::HandleObject obj); - /***********************************************/ // XPCWrappedNativeTearOff represents the info needed to make calls to one // interface on the underlying native object of a XPCWrappedNative. @@ -2489,22 +2477,6 @@ public: XPCNativeInterface* Interface, XPCWrappedNative** wrapper); - static XPCWrappedNative* - GetAndMorphWrappedNativeOfJSObject(JSContext* cx, JSObject* obj_) - { - JS::RootedObject obj(cx, obj_); - obj = js::CheckedUnwrap(obj, /* stopAtOuter = */ false); - if (!obj) - return nullptr; - if (!IS_WRAPPER_CLASS(js::GetObjectClass(obj))) - return nullptr; - - if (IS_SLIM_WRAPPER_OBJECT(obj) && !MorphSlimWrapper(cx, obj)) - return nullptr; - MOZ_ASSERT(IS_WN_WRAPPER(obj)); - return XPCWrappedNative::Get(obj); - } - static nsresult ReparentWrapperIfFound(XPCWrappedNativeScope* aOldScope, XPCWrappedNativeScope* aNewScope, @@ -2668,7 +2640,6 @@ private: private: JSBool Init(JS::HandleObject parent, const XPCNativeScriptableCreateInfo* sci); - JSBool Init(JSObject *existingJSObject); JSBool FinishInit(); JSBool ExtendSet(XPCNativeInterface* aInterface); diff --git a/js/xpconnect/src/xpcpublic.h b/js/xpconnect/src/xpcpublic.h index 1ce3db287c84..bc14096cc030 100644 --- a/js/xpconnect/src/xpcpublic.h +++ b/js/xpconnect/src/xpcpublic.h @@ -82,9 +82,6 @@ xpc_LocalizeRuntime(JSRuntime *rt); NS_EXPORT_(void) xpc_DelocalizeRuntime(JSRuntime *rt); -nsresult -xpc_MorphSlimWrapper(JSContext *cx, nsISupports *tomorph); - static inline bool IS_WRAPPER_CLASS(js::Class* clazz) { return clazz->ext.isWrappedNative; diff --git a/js/xpconnect/wrappers/WrapperFactory.cpp b/js/xpconnect/wrappers/WrapperFactory.cpp index 1edeb8e67847..060f9511b0ab 100644 --- a/js/xpconnect/wrappers/WrapperFactory.cpp +++ b/js/xpconnect/wrappers/WrapperFactory.cpp @@ -152,11 +152,6 @@ WrapperFactory::PrepareForWrapping(JSContext *cx, HandleObject scope, // We should never get a proxy here (the JS engine unwraps those for us). MOZ_ASSERT(!IsWrapper(obj)); - // As soon as an object is wrapped in a security wrapper, it morphs to be - // a fat wrapper. (see also: bug XXX). - if (IS_SLIM_WRAPPER(obj) && !MorphSlimWrapper(cx, obj)) - return nullptr; - // If the object being wrapped is a prototype for a standard class and the // wrapper does not subsumes the wrappee, use the one from the content // compartment. This is generally safer all-around, and in the COW case this From e246f74b5d4098d44e468fa7b9e5ad1b3723cb73 Mon Sep 17 00:00:00 2001 From: Peter Van der Beken Date: Fri, 19 Apr 2013 21:57:18 +0200 Subject: [PATCH 20/84] Bug 851465 - Remove slim wrappers - remove various slim wrapper code and checks. r=bholley. --- dom/bindings/BindingUtils.h | 39 +++++++++------------ js/xpconnect/src/XPCCallContext.cpp | 8 ++--- js/xpconnect/src/XPCConvert.cpp | 6 ++-- js/xpconnect/src/XPCJSID.cpp | 3 +- js/xpconnect/src/XPCJSRuntime.cpp | 6 +--- js/xpconnect/src/XPCQuickStubs.cpp | 29 ++++------------ js/xpconnect/src/XPCWrappedNative.cpp | 5 ++- js/xpconnect/src/XPCWrappedNativeJSOps.cpp | 40 ++-------------------- js/xpconnect/src/nsXPConnect.cpp | 4 +-- js/xpconnect/src/xpcprivate.h | 7 ---- js/xpconnect/src/xpcpublic.h | 6 +--- js/xpconnect/wrappers/XrayWrapper.cpp | 6 ++-- 12 files changed, 40 insertions(+), 119 deletions(-) diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index 25fa820284ef..aab790d2a780 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -535,29 +535,24 @@ MaybeWrapValue(JSContext* cx, JS::MutableHandle rval) return true; } - if (rval.isObject()) { - JSObject* obj = &rval.toObject(); - if (js::GetObjectCompartment(obj) != js::GetContextCompartment(cx)) { - return JS_WrapValue(cx, rval.address()); - } - - // We're same-compartment, but even then we might need to wrap - // objects specially. Check for that. - if (GetSameCompartmentWrapperForDOMBinding(obj)) { - // We're a new-binding object, and "obj" now points to the right thing - rval.set(JS::ObjectValue(*obj)); - return true; - } - - if (!IS_SLIM_WRAPPER(obj)) { - // We might need a SOW - return JS_WrapValue(cx, rval.address()); - } - - // Fall through to returning true + if (!rval.isObject()) { + return true; } - return true; + JSObject* obj = &rval.toObject(); + if (js::GetObjectCompartment(obj) != js::GetContextCompartment(cx)) { + return JS_WrapValue(cx, rval.address()); + } + + // We're same-compartment, but even then we might need to wrap + // objects specially. Check for that. + if (GetSameCompartmentWrapperForDOMBinding(obj)) { + // We're a new-binding object, and "obj" now points to the right thing + rval.set(JS::ObjectValue(*obj)); + return true; + } + + return JS_WrapValue(cx, rval.address()); } static inline void @@ -642,7 +637,7 @@ WrapNewBindingObject(JSContext* cx, JS::Handle scope, T* value, } rval.set(JS::ObjectValue(*obj)); - return (sameCompartment && IS_SLIM_WRAPPER(obj)) || JS_WrapValue(cx, rval.address()); + return JS_WrapValue(cx, rval.address()); } // Create a JSObject wrapping "value", for cases when "value" is a diff --git a/js/xpconnect/src/XPCCallContext.cpp b/js/xpconnect/src/XPCCallContext.cpp index ca20ff70711b..41f67570e8a1 100644 --- a/js/xpconnect/src/XPCCallContext.cpp +++ b/js/xpconnect/src/XPCCallContext.cpp @@ -99,10 +99,7 @@ XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage, } else { js::Class *clasp = js::GetObjectClass(unwrapped); if (IS_WRAPPER_CLASS(clasp)) { - if (IS_SLIM_WRAPPER_OBJECT(unwrapped)) - mFlattenedJSObject = unwrapped; - else - mWrapper = XPCWrappedNative::Get(unwrapped); + mWrapper = XPCWrappedNative::Get(unwrapped); } else if (IS_TEAROFF_CLASS(clasp)) { mTearOff = (XPCWrappedNativeTearOff*)js::GetObjectPrivate(unwrapped); mWrapper = XPCWrappedNative::Get(js::GetObjectParent(unwrapped)); @@ -116,8 +113,7 @@ XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage, else mScriptableInfo = mWrapper->GetScriptableInfo(); } else { - NS_ABORT_IF_FALSE(!mFlattenedJSObject || IS_SLIM_WRAPPER(mFlattenedJSObject), - "should have a slim wrapper"); + NS_ABORT_IF_FALSE(!mFlattenedJSObject, "What object do we have?"); } if (!JSID_IS_VOID(name)) diff --git a/js/xpconnect/src/XPCConvert.cpp b/js/xpconnect/src/XPCConvert.cpp index 20309e8b58b6..c20fd223ceba 100644 --- a/js/xpconnect/src/XPCConvert.cpp +++ b/js/xpconnect/src/XPCConvert.cpp @@ -838,8 +838,6 @@ XPCConvert::NativeInterface2JSObject(jsval* d, return CreateHolderIfNeeded(flat, d, dest); } } - - MOZ_ASSERT_IF(flat, !IS_SLIM_WRAPPER_OBJECT(flat)); } else { flat = nullptr; } @@ -875,7 +873,9 @@ XPCConvert::NativeInterface2JSObject(jsval* d, getter_AddRefs(strongWrapper)); wrapper = strongWrapper; - } else if (IS_WN_WRAPPER_OBJECT(flat)) { + } else { + MOZ_ASSERT(IS_WN_WRAPPER_OBJECT(flat)); + wrapper = static_cast(xpc_GetJSPrivate(flat)); // If asked to return the wrapper we'll return a strong reference, diff --git a/js/xpconnect/src/XPCJSID.cpp b/js/xpconnect/src/XPCJSID.cpp index 477eb1e9590d..c194d94798f1 100644 --- a/js/xpconnect/src/XPCJSID.cpp +++ b/js/xpconnect/src/XPCJSID.cpp @@ -470,8 +470,7 @@ nsJSIID::Enumerate(nsIXPConnectWrappedNative *wrapper, * there's chrome code that relies on this. * * This static method handles both complexities, returning either an XPCWN, a - * slim wrapper, a DOM object, or null. The object may well be cross-compartment - * from |cx|. + * DOM object, or null. The object may well be cross-compartment from |cx|. */ static JSObject * FindObjectForHasInstance(JSContext *cx, HandleObject objArg) diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index cd3e312f7845..5f9118467bf3 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -2540,11 +2540,7 @@ PreserveWrapper(JSContext *cx, JSObject *objArg) if (!IS_WRAPPER_CLASS(js::GetObjectClass(obj))) return mozilla::dom::TryPreserveWrapper(obj); - nsISupports *supports = nullptr; - if (IS_WN_WRAPPER_OBJECT(obj)) - supports = XPCWrappedNative::Get(obj)->Native(); - else - supports = static_cast(xpc_GetJSPrivate(obj)); + nsISupports *supports = XPCWrappedNative::Get(obj)->Native(); // For pre-Paris DOM bindings objects, we only support Node. if (nsCOMPtr node = do_QueryInterface(supports)) { diff --git a/js/xpconnect/src/XPCQuickStubs.cpp b/js/xpconnect/src/XPCQuickStubs.cpp index 924b95f33b6d..f09fadf05d59 100644 --- a/js/xpconnect/src/XPCQuickStubs.cpp +++ b/js/xpconnect/src/XPCQuickStubs.cpp @@ -565,14 +565,10 @@ getWrapper(JSContext *cx, obj = js::GetObjectParent(obj); } - // If we've got a WN or slim wrapper, store things the way callers expect. - // Otherwise, leave things null and return. - if (IS_WRAPPER_CLASS(clasp)) { - if (IS_WN_WRAPPER_OBJECT(obj)) - *wrapper = (XPCWrappedNative*) js::GetObjectPrivate(obj); - else - *cur = obj; - } + // If we've got a WN, store things the way callers expect. Otherwise, leave + // things null and return. + if (IS_WRAPPER_CLASS(clasp)) + *wrapper = XPCWrappedNative::Get(obj); return NS_OK; } @@ -597,12 +593,8 @@ castNative(JSContext *cx, } else if (cur) { nsISupports *native; if (!(native = mozilla::dom::UnwrapDOMObjectToISupports(cur))) { - if (IS_SLIM_WRAPPER(cur)) { - native = static_cast(xpc_GetJSPrivate(cur)); - } else { - *pThisRef = nullptr; - return NS_ERROR_ILLEGAL_VALUE; - } + *pThisRef = nullptr; + return NS_ERROR_ILLEGAL_VALUE; } if (NS_SUCCEEDED(getNative(native, cur, iid, ppThis, pThisRef, vp))) { @@ -630,9 +622,7 @@ castNativeFromWrapper(JSContext *cx, if (IS_WRAPPER_CLASS(js::GetObjectClass(obj))) { cur = obj; - wrapper = IS_WN_WRAPPER_OBJECT(cur) ? - (XPCWrappedNative*)xpc_GetJSPrivate(obj) : - nullptr; + wrapper = (XPCWrappedNative*)xpc_GetJSPrivate(obj); tearoff = nullptr; } else { *rv = getWrapper(cx, obj, &wrapper, &cur, &tearoff); @@ -647,11 +637,6 @@ castNativeFromWrapper(JSContext *cx, if (!native || !HasBitInInterfacesBitmap(cur, interfaceBit)) { native = nullptr; } - } else if (cur && IS_SLIM_WRAPPER(cur)) { - native = static_cast(xpc_GetJSPrivate(cur)); - if (!native || !HasBitInInterfacesBitmap(cur, interfaceBit)) { - native = nullptr; - } } else if (cur && protoDepth >= 0) { const mozilla::dom::DOMClass* domClass = mozilla::dom::GetDOMClass(cur); diff --git a/js/xpconnect/src/XPCWrappedNative.cpp b/js/xpconnect/src/XPCWrappedNative.cpp index 9d60bd2ba756..fb3e59614e9b 100644 --- a/js/xpconnect/src/XPCWrappedNative.cpp +++ b/js/xpconnect/src/XPCWrappedNative.cpp @@ -1320,7 +1320,7 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCWrappedNativeScope* aOldScope, CallQueryInterface(aCOMObj, &cache); if (cache) { flat = cache->GetWrapper(); - if (flat && !IS_SLIM_WRAPPER_OBJECT(flat)) { + if (flat) { wrapper = static_cast(xpc_GetJSPrivate(flat)); NS_ASSERTION(wrapper->GetScope() == aOldScope, "Incorrect scope passed"); @@ -1341,8 +1341,7 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCWrappedNativeScope* aOldScope, // ReparentWrapperIfFound is really only meant to be called from DOM code // which must happen only on the main thread. Bail if we're on some other // thread or have a non-main-thread-only wrapper. - if (wrapper && - wrapper->GetProto() && + if (wrapper->GetProto() && !wrapper->GetProto()->ClassIsMainThreadOnly()) { return NS_ERROR_FAILURE; } diff --git a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp index 4954a7aedbfd..2b987e553408 100644 --- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp +++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp @@ -593,10 +593,6 @@ XPC_WN_Shared_Enumerate(JSContext *cx, JSHandleObject obj) /***************************************************************************/ -#ifdef DEBUG_slimwrappers -static uint32_t sFinalizedSlimWrappers; -#endif - enum WNHelperType { WN_NOHELPER, WN_HELPER @@ -613,20 +609,6 @@ WrappedNativeFinalize(js::FreeOp *fop, JSObject *obj, WNHelperType helperType) if (!p) return; - if (IS_SLIM_WRAPPER_OBJECT(obj)) { - SLIM_LOG(("----- %i finalized slim wrapper (%p, %p)\n", - ++sFinalizedSlimWrappers, obj, p)); - - nsWrapperCache* cache; - CallQueryInterface(p, &cache); - cache->ClearWrapper(); - - XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance(); - MOZ_ASSERT(rt, "XPCJSRuntime should exist during a GC."); - rt->DeferredRelease(p); - return; - } - XPCWrappedNative* wrapper = static_cast(p); if (helperType == WN_HELPER) wrapper->GetScriptableCallback()->Finalize(wrapper, js::CastToJSFreeOp(fop), obj); @@ -639,12 +621,6 @@ XPC_WN_NoHelper_Finalize(js::FreeOp *fop, JSObject *obj) WrappedNativeFinalize(fop, obj, WN_NOHELPER); } -static void -TraceInsideSlimWrapper(JSTracer *trc, JSObject *obj) -{ - GetSlimWrapperProto(obj)->TraceSelf(trc); -} - /* * General comment about XPConnect tracing: Given a C++ object |wrapper| and its * corresponding JS object |obj|, calling |wrapper->TraceSelf| will ask the JS @@ -662,16 +638,9 @@ MarkWrappedNative(JSTracer *trc, JSObject *obj) } MOZ_ASSERT(IS_WRAPPER_CLASS(clazz)); - if (IS_WN_WRAPPER_OBJECT(obj)) { - XPCWrappedNative *wrapper = XPCWrappedNative::Get(obj); - if (wrapper) { - if (wrapper->IsValid()) - wrapper->TraceInside(trc); - } - } else { - MOZ_ASSERT(IS_SLIM_WRAPPER_OBJECT(obj)); - TraceInsideSlimWrapper(trc, obj); - } + XPCWrappedNative *wrapper = XPCWrappedNative::Get(obj); + if (wrapper && wrapper->IsValid()) + wrapper->TraceInside(trc); } static void @@ -1371,9 +1340,6 @@ XPCNativeScriptableShared::PopulateJSClass() if (mFlags.WantOuterObject()) mJSClass.base.ext.outerObject = XPC_WN_OuterObject; - if (!(mFlags & nsIXPCScriptable::WANT_OUTER_OBJECT)) - mCanBeSlim = true; - mJSClass.base.ext.isWrappedNative = true; } diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index 1d48c27d7807..576ed933be49 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -1246,9 +1246,7 @@ nsXPConnect::GetNativeOfWrapper(JSContext * aJSContext, return nullptr; } if (IS_WRAPPER_CLASS(js::GetObjectClass(aJSObj))) { - if (IS_SLIM_WRAPPER_OBJECT(aJSObj)) - return (nsISupports*)xpc_GetJSPrivate(aJSObj); - else if (XPCWrappedNative *wn = XPCWrappedNative::Get(aJSObj)) + if (XPCWrappedNative *wn = XPCWrappedNative::Get(aJSObj)) return wn->Native(); return nullptr; } diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 83d9068d0781..6bf0878b1b31 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -15,13 +15,6 @@ * additional C++ object involved of type XPCWrappedNative. The XPCWrappedNative * holds pointers to the C++ object and the flat JS object. * - * As an optimization, some C++ objects don't have XPCWrappedNatives, although - * they still have a corresponding flattened JS object. These are called "slim - * wrappers": all the wrapping information is stored in extra fields of the C++ - * object and the JS object. Slim wrappers are only used for DOM objects. As a - * deoptimization, slim wrappers can be "morphed" into XPCWrappedNatives if the - * extra fields of the XPCWrappedNative become necessary. - * * All XPCWrappedNative objects belong to an XPCWrappedNativeScope. These scopes * are essentially in 1:1 correspondence with JS global objects. The * XPCWrappedNativeScope has a pointer to the JS global object. The parent of a diff --git a/js/xpconnect/src/xpcpublic.h b/js/xpconnect/src/xpcpublic.h index bc14096cc030..6b9fd1af0759 100644 --- a/js/xpconnect/src/xpcpublic.h +++ b/js/xpconnect/src/xpcpublic.h @@ -131,14 +131,10 @@ xpc_FastGetCachedWrapper(nsWrapperCache *cache, JSObject *scope, jsval *vp) { if (cache) { JSObject* wrapper = cache->GetWrapper(); - NS_ASSERTION(!wrapper || - !cache->IsDOMBinding() || - !IS_SLIM_WRAPPER(wrapper), - "Should never have a slim wrapper when IsDOMBinding()"); if (wrapper && js::GetObjectCompartment(wrapper) == js::GetObjectCompartment(scope) && (cache->IsDOMBinding() ? !cache->HasSystemOnlyWrapper() : - (IS_SLIM_WRAPPER(wrapper) || xpc_OkToHandOutWrapper(cache)))) { + xpc_OkToHandOutWrapper(cache))) { *vp = OBJECT_TO_JSVAL(wrapper); return wrapper; } diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index 548a8fd98477..070c50f8d7bf 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -61,11 +61,9 @@ GetXrayType(JSObject *obj) return XrayForDOMObject; js::Class* clasp = js::GetObjectClass(obj); - if (IS_WRAPPER_CLASS(clasp) || clasp->ext.innerObject) { - NS_ASSERTION(clasp->ext.innerObject || IS_WN_WRAPPER_OBJECT(obj), - "We forgot to Morph a slim wrapper!"); + if (IS_WRAPPER_CLASS(clasp) || clasp->ext.innerObject) return XrayForWrappedNative; - } + return NotXray; } From b853c731c082357981adbaa73a9381b5903e752e Mon Sep 17 00:00:00 2001 From: Peter Van der Beken Date: Fri, 19 Apr 2013 21:58:26 +0200 Subject: [PATCH 21/84] Bug 851465 - Remove slim wrappers - remove slim wrapper proto code and logging code. r=bholley. --- js/xpconnect/src/XPCInlines.h | 4 +- js/xpconnect/src/XPCJSID.cpp | 4 +- js/xpconnect/src/XPCLog.cpp | 33 ----------- js/xpconnect/src/XPCLog.h | 54 ------------------ js/xpconnect/src/XPCQuickStubs.cpp | 12 +--- js/xpconnect/src/XPCWrappedNative.cpp | 12 +--- js/xpconnect/src/XPCWrappedNativeJSOps.cpp | 65 ++-------------------- js/xpconnect/src/nsXPConnect.cpp | 17 ------ js/xpconnect/src/xpcprivate.h | 12 ---- 9 files changed, 10 insertions(+), 203 deletions(-) diff --git a/js/xpconnect/src/XPCInlines.h b/js/xpconnect/src/XPCInlines.h index c17dec24cf23..30a303b9aabb 100644 --- a/js/xpconnect/src/XPCInlines.h +++ b/js/xpconnect/src/XPCInlines.h @@ -121,9 +121,7 @@ inline XPCWrappedNativeProto* XPCCallContext::GetProto() const { CHECK_STATE(HAVE_OBJECT); - if (mWrapper) - return mWrapper->GetProto(); - return mFlattenedJSObject ? GetSlimWrapperProto(mFlattenedJSObject) : nullptr; + return mWrapper ? mWrapper->GetProto() : nullptr; } inline JSBool diff --git a/js/xpconnect/src/XPCJSID.cpp b/js/xpconnect/src/XPCJSID.cpp index c194d94798f1..1628d9a38d41 100644 --- a/js/xpconnect/src/XPCJSID.cpp +++ b/js/xpconnect/src/XPCJSID.cpp @@ -843,9 +843,7 @@ nsJSCID::HasInstance(nsIXPConnectWrappedNative *wrapper, obj = FindObjectForHasInstance(cx, obj); if (!obj || !IS_WRAPPER_CLASS(js::GetObjectClass(obj))) return rv; - if (IS_SLIM_WRAPPER_OBJECT(obj)) - ci = GetSlimWrapperProto(obj)->GetClassInfo(); - else if (XPCWrappedNative* other_wrapper = XPCWrappedNative::Get(obj)) + if (XPCWrappedNative* other_wrapper = XPCWrappedNative::Get(obj)) ci = other_wrapper->GetClassInfo(); // We consider CID equality to be the thing that matters here. diff --git a/js/xpconnect/src/XPCLog.cpp b/js/xpconnect/src/XPCLog.cpp index eebe50fb98c8..c659183dc9c0 100644 --- a/js/xpconnect/src/XPCLog.cpp +++ b/js/xpconnect/src/XPCLog.cpp @@ -90,36 +90,3 @@ XPC_Log_Clear_Indent() } #endif - -#ifdef DEBUG_slimwrappers -void -LogSlimWrapperWillMorph(JSContext *cx, JSObject *obj, const char *propname, - const char *functionName) -{ - if (obj && IS_SLIM_WRAPPER(obj)) { - XPCNativeScriptableInfo *si = - GetSlimWrapperProto(obj)->GetScriptableInfo(); - printf("***** morphing %s from %s", si->GetJSClass()->name, - functionName); - if (propname) - printf(" for %s", propname); - printf(" (%p, %p)\n", obj, - static_cast(xpc_GetJSPrivate(obj))); - xpc_DumpJSStack(cx, false, false, false); - } -} - -void -LogSlimWrapperNotCreated(JSContext *cx, nsISupports *obj, const char *reason) -{ - char* className = nullptr; - nsCOMPtr ci = do_QueryInterface(obj); - if (ci) - ci->GetClassDescription(&className); - printf("***** refusing to create slim wrapper%s%s, reason: %s (%p)\n", - className ? " for " : "", className ? className : "", reason, obj); - if (className) - PR_Free(className); - xpc_DumpJSStack(cx, false, false, false); -} -#endif diff --git a/js/xpconnect/src/XPCLog.h b/js/xpconnect/src/XPCLog.h index 42b8c08ec999..7bf52900ae58 100644 --- a/js/xpconnect/src/XPCLog.h +++ b/js/xpconnect/src/XPCLog.h @@ -64,58 +64,4 @@ JS_END_EXTERN_C #define XPC_LOG_FINISH() ((void)0) #endif - -#ifdef DEBUG_peterv -#define DEBUG_slimwrappers 1 -#endif - -#ifdef DEBUG_slimwrappers -extern void LogSlimWrapperWillMorph(JSContext *cx, JSObject *obj, - const char *propname, - const char *functionName); -extern void LogSlimWrapperNotCreated(JSContext *cx, nsISupports *obj, - const char *reason); - -#define SLIM_LOG_WILL_MORPH_FOR_PROP(cx, obj, prop) \ - PR_BEGIN_MACRO \ - LogSlimWrapperWillMorph(cx, obj, (const char*)prop, __FUNCTION__); \ - PR_END_MACRO -#define SLIM_LOG_WILL_MORPH_FOR_ID(cx, obj, id) \ - PR_BEGIN_MACRO \ - JSString* strId = ::JS_ValueToString(cx, id); \ - if (strId) { \ - NS_ConvertUTF16toUTF8 name((PRUnichar*)::JS_GetStringChars(strId), \ - ::JS_GetStringLength(strId)); \ - LOG_WILL_MORPH_FOR_PROP(cx, obj, name.get()); \ - } \ - else \ - { \ - LOG_WILL_MORPH_FOR_PROP(cx, obj, nullptr); \ - } \ - PR_END_MACRO -#define SLIM_LOG_NOT_CREATED(cx, obj, reason) \ - PR_BEGIN_MACRO \ - LogSlimWrapperNotCreated(cx, obj, reason); \ - PR_END_MACRO -#define SLIM_LOG(_args) \ - PR_BEGIN_MACRO \ - printf _args; \ - PR_END_MACRO -#else -#define SLIM_LOG_WILL_MORPH_FOR_PROP(cx, obj, prop) \ - PR_BEGIN_MACRO \ - PR_END_MACRO -#define SLIM_LOG_WILL_MORPH_FOR_ID(cx, obj) \ - PR_BEGIN_MACRO \ - PR_END_MACRO -#define SLIM_LOG_NOT_CREATED(cx, obj, reason) \ - PR_BEGIN_MACRO \ - PR_END_MACRO -#define SLIM_LOG(_args) \ - PR_BEGIN_MACRO \ - PR_END_MACRO -#endif -#define SLIM_LOG_WILL_MORPH(cx, obj) \ - SLIM_LOG_WILL_MORPH_FOR_PROP(cx, obj, nullptr) - #endif /* xpclog_h___ */ diff --git a/js/xpconnect/src/XPCQuickStubs.cpp b/js/xpconnect/src/XPCQuickStubs.cpp index f09fadf05d59..315ed19498e3 100644 --- a/js/xpconnect/src/XPCQuickStubs.cpp +++ b/js/xpconnect/src/XPCQuickStubs.cpp @@ -179,15 +179,9 @@ GetMemberInfo(JSObject *obj, jsid memberId, const char **ifaceName) // an error message. Instead, only handle the simple case where we have the // reflector in hand. if (IS_WRAPPER_CLASS(js::GetObjectClass(obj))) { - XPCWrappedNativeProto *proto; - if (IS_SLIM_WRAPPER_OBJECT(obj)) { - proto = GetSlimWrapperProto(obj); - } else { - MOZ_ASSERT(IS_WN_WRAPPER_OBJECT(obj)); - XPCWrappedNative *wrapper = - static_cast(js::GetObjectPrivate(obj)); - proto = wrapper->GetProto(); - } + XPCWrappedNative *wrapper = + static_cast(js::GetObjectPrivate(obj)); + XPCWrappedNativeProto *proto = wrapper->GetProto(); if (proto) { XPCNativeSet *set = proto->GetSet(); if (set) { diff --git a/js/xpconnect/src/XPCWrappedNative.cpp b/js/xpconnect/src/XPCWrappedNative.cpp index fb3e59614e9b..c88a66ecfc00 100644 --- a/js/xpconnect/src/XPCWrappedNative.cpp +++ b/js/xpconnect/src/XPCWrappedNative.cpp @@ -1357,11 +1357,8 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCWrappedNativeScope* aOldScope, MOZ_ASSERT(js::GetObjectCompartment(aOldScope->GetGlobalJSObject()) != js::GetObjectCompartment(aNewScope->GetGlobalJSObject())); NS_ASSERTION(aNewParent, "won't be able to find the new parent"); - NS_ASSERTION(wrapper, "can't transplant slim wrappers"); - if (!wrapper) - oldProto = GetSlimWrapperProto(flat); - else if (wrapper->HasProto()) + if (wrapper->HasProto()) oldProto = wrapper->GetProto(); if (oldProto) { @@ -1376,8 +1373,6 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCWrappedNativeScope* aOldScope, } } - if (wrapper) { - // First, the clone of the reflector, get a copy of its // properties and clone its expando chain. The only part that is // dangerous here if we have to return early is that we must avoid @@ -1501,11 +1496,6 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCWrappedNativeScope* aOldScope, } if (!JS_CopyPropertiesFrom(cx, flat, propertyHolder)) MOZ_CRASH(); - } else { - SetSlimWrapperProto(flat, newProto.get()); - if (!JS_SetPrototype(cx, flat, newProto->GetJSProtoObject())) - MOZ_CRASH(); // this is bad, very bad - } // Call the scriptable hook to indicate that we transplanted. XPCNativeScriptableInfo* si = wrapper->GetScriptableInfo(); diff --git a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp index 2b987e553408..99aa28d91435 100644 --- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp +++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp @@ -74,32 +74,6 @@ XPC_WN_Shared_ToString(JSContext *cx, unsigned argc, jsval *vp) if (!obj) return false; - if (IS_SLIM_WRAPPER(obj)) { - XPCNativeScriptableInfo *si = - GetSlimWrapperProto(obj)->GetScriptableInfo(); -#ifdef DEBUG -# define FMT_ADDR " @ 0x%p" -# define FMT_STR(str) str -# define PARAM_ADDR(w) , w -#else -# define FMT_ADDR "" -# define FMT_STR(str) -# define PARAM_ADDR(w) -#endif - char *sz = JS_smprintf("[object %s" FMT_ADDR FMT_STR(" (native") FMT_ADDR FMT_STR(")") "]", si->GetJSClass()->name PARAM_ADDR(obj.get()) PARAM_ADDR(xpc_GetJSPrivate(obj))); - if (!sz) - return false; - - JSString* str = JS_NewStringCopyZ(cx, sz); - JS_smprintf_free(sz); - if (!str) - return false; - - *vp = STRING_TO_JSVAL(str); - - return true; - } - XPCCallContext ccx(JS_CALLER, cx, obj); if (!ccx.IsValid()) return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); @@ -816,9 +790,7 @@ XPC_WN_MaybeResolvingDeletePropertyStub(JSContext *cx, JSHandleObject obj, JSHan // macro fun! #define PRE_HELPER_STUB \ - XPCWrappedNative* wrapper; \ - nsIXPCScriptable* si; \ - JSObject *unwrapped = js::CheckedUnwrap(obj, false); \ + JSObject *unwrapped = js::CheckedUnwrap(obj, false); \ if (!unwrapped) { \ JS_ReportError(cx, "Permission denied to operate on object."); \ return false; \ @@ -826,18 +798,10 @@ XPC_WN_MaybeResolvingDeletePropertyStub(JSContext *cx, JSHandleObject obj, JSHan if (!IS_WRAPPER_CLASS(js::GetObjectClass(unwrapped))) { \ return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); \ } \ - if (IS_SLIM_WRAPPER_OBJECT(unwrapped)) { \ - wrapper = nullptr; \ - si = GetSlimWrapperProto(unwrapped)->GetScriptableInfo() \ - ->GetCallback(); \ - } else { \ - MOZ_ASSERT(IS_WN_WRAPPER_OBJECT(unwrapped)); \ - wrapper = XPCWrappedNative::Get(unwrapped); \ - THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); \ - si = wrapper->GetScriptableCallback(); \ - } \ + XPCWrappedNative *wrapper = XPCWrappedNative::Get(unwrapped); \ + THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); \ bool retval = true; \ - nsresult rv = si-> + nsresult rv = wrapper->GetScriptableCallback()-> #define POST_HELPER_STUB \ if (NS_FAILED(rv)) \ @@ -959,27 +923,6 @@ XPC_WN_Helper_NewResolve(JSContext *cx, JSHandleObject obj, JSHandleId id, unsig nsresult rv = NS_OK; bool retval = true; RootedObject obj2FromScriptable(cx); - if (IS_SLIM_WRAPPER(obj)) { - XPCNativeScriptableInfo *si = - GetSlimWrapperProto(obj)->GetScriptableInfo(); - if (!si->GetFlags().WantNewResolve()) - return retval; - - NS_ASSERTION(si->GetFlags().AllowPropModsToPrototype() && - !si->GetFlags().AllowPropModsDuringResolve(), - "We don't support these flags for slim wrappers!"); - - rv = si->GetCallback()->NewResolve(nullptr, cx, obj, id, flags, - obj2FromScriptable.address(), &retval); - if (NS_FAILED(rv)) - return Throw(rv, cx); - - if (obj2FromScriptable) - objp.set(obj2FromScriptable); - - return retval; - } - XPCCallContext ccx(JS_CALLER, cx, obj); XPCWrappedNative* wrapper = ccx.GetWrapper(); THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index 576ed933be49..b13d5bb90059 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -1942,23 +1942,6 @@ nsXPConnect::GetPrincipal(JSObject* obj, bool allowShortCircuit) const } } } - } else { - if (allowShortCircuit) { - nsIPrincipal *result = - GetSlimWrapperProto(obj)->GetScope()->GetPrincipal(); - if (result) { - return result; - } - } - - nsCOMPtr objPrin = - do_QueryInterface((nsISupports*)xpc_GetJSPrivate(obj)); - if (objPrin) { - nsIPrincipal *result = objPrin->GetPrincipal(); - if (result) { - return result; - } - } } return nullptr; diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 6bf0878b1b31..8722472ae9ff 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -285,18 +285,6 @@ extern const char XPC_XPCONNECT_CONTRACTID[]; #define INVALID_OBJECT ((JSObject *)1) -inline void SetSlimWrapperProto(JSObject *obj, XPCWrappedNativeProto *proto) -{ - JS_SetReservedSlot(obj, WRAPPER_MULTISLOT, PRIVATE_TO_JSVAL(proto)); -} - -inline XPCWrappedNativeProto* GetSlimWrapperProto(JSObject *obj) -{ - MOZ_ASSERT(IS_SLIM_WRAPPER(obj)); - const JS::Value &v = js::GetReservedSlot(obj, WRAPPER_MULTISLOT); - return static_cast(v.toPrivate()); -} - inline void SetWNExpandoChain(JSObject *obj, JSObject *chain) { MOZ_ASSERT(IS_WN_WRAPPER(obj)); From 39efb11a1e7ba2b8e141c9235e5f2327948bfd23 Mon Sep 17 00:00:00 2001 From: Peter Van der Beken Date: Fri, 19 Apr 2013 21:58:26 +0200 Subject: [PATCH 22/84] Bug 851465 - Remove slim wrappers - whitespace changes. r=bholley. --- js/xpconnect/src/XPCWrappedNative.cpp | 228 +++++++++++++------------- 1 file changed, 114 insertions(+), 114 deletions(-) diff --git a/js/xpconnect/src/XPCWrappedNative.cpp b/js/xpconnect/src/XPCWrappedNative.cpp index c88a66ecfc00..49abed097bec 100644 --- a/js/xpconnect/src/XPCWrappedNative.cpp +++ b/js/xpconnect/src/XPCWrappedNative.cpp @@ -1373,130 +1373,130 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCWrappedNativeScope* aOldScope, } } - // First, the clone of the reflector, get a copy of its - // properties and clone its expando chain. The only part that is - // dangerous here if we have to return early is that we must avoid - // ending up with two reflectors pointing to the same WN. Other than - // that, the objects we create will just go away if we return early. + // First, the clone of the reflector, get a copy of its + // properties and clone its expando chain. The only part that is + // dangerous here if we have to return early is that we must avoid + // ending up with two reflectors pointing to the same WN. Other than + // that, the objects we create will just go away if we return early. - RootedObject newobj(cx, JS_CloneObject(cx, flat, - newProto->GetJSProtoObject(), - aNewParent)); - if (!newobj) + RootedObject newobj(cx, JS_CloneObject(cx, flat, + newProto->GetJSProtoObject(), + aNewParent)); + if (!newobj) + return NS_ERROR_FAILURE; + + // At this point, both |flat| and |newobj| point to the same wrapped + // native, which is bad, because one of them will end up finalizing + // a wrapped native it does not own. |cloneGuard| ensures that if we + // exit before calling clearing |flat|'s private the private of + // |newobj| will be set to NULL. |flat| will go away soon, because + // we swap it with another object during the transplant and let that + // object die. + RootedObject propertyHolder(cx); + { + AutoClonePrivateGuard cloneGuard(cx, flat, newobj); + + propertyHolder = JS_NewObjectWithGivenProto(cx, NULL, NULL, aNewParent); + if (!propertyHolder) + return NS_ERROR_OUT_OF_MEMORY; + if (!JS_CopyPropertiesFrom(cx, propertyHolder, flat)) return NS_ERROR_FAILURE; - // At this point, both |flat| and |newobj| point to the same wrapped - // native, which is bad, because one of them will end up finalizing - // a wrapped native it does not own. |cloneGuard| ensures that if we - // exit before calling clearing |flat|'s private the private of - // |newobj| will be set to NULL. |flat| will go away soon, because - // we swap it with another object during the transplant and let that - // object die. - RootedObject propertyHolder(cx); - { - AutoClonePrivateGuard cloneGuard(cx, flat, newobj); + // Expandos from other compartments are attached to the target JS object. + // Copy them over, and let the old ones die a natural death. + SetWNExpandoChain(newobj, nullptr); + if (!XrayUtils::CloneExpandoChain(cx, newobj, flat)) + return NS_ERROR_FAILURE; - propertyHolder = JS_NewObjectWithGivenProto(cx, NULL, NULL, aNewParent); - if (!propertyHolder) - return NS_ERROR_OUT_OF_MEMORY; - if (!JS_CopyPropertiesFrom(cx, propertyHolder, flat)) - return NS_ERROR_FAILURE; + // We've set up |newobj|, so we make it own the WN by nulling out + // the private of |flat|. + // + // NB: It's important to do this _after_ copying the properties to + // propertyHolder. Otherwise, an object with |foo.x === foo| will + // crash when JS_CopyPropertiesFrom tries to call wrap() on foo.x. + JS_SetPrivate(flat, nullptr); + } - // Expandos from other compartments are attached to the target JS object. - // Copy them over, and let the old ones die a natural death. - SetWNExpandoChain(newobj, nullptr); - if (!XrayUtils::CloneExpandoChain(cx, newobj, flat)) - return NS_ERROR_FAILURE; + // Before proceeding, eagerly create any same-compartment security wrappers + // that the object might have. This forces us to take the 'WithWrapper' path + // while transplanting that handles this stuff correctly. + { + JSAutoCompartment innerAC(cx, aOldScope->GetGlobalJSObject()); + if (!wrapper->GetSameCompartmentSecurityWrapper(cx)) + return NS_ERROR_FAILURE; + } - // We've set up |newobj|, so we make it own the WN by nulling out - // the private of |flat|. - // - // NB: It's important to do this _after_ copying the properties to - // propertyHolder. Otherwise, an object with |foo.x === foo| will - // crash when JS_CopyPropertiesFrom tries to call wrap() on foo.x. - JS_SetPrivate(flat, nullptr); + // Update scope maps. This section modifies global state, so from + // here on out we crash if anything fails. + { // scoped lock + Native2WrappedNativeMap* oldMap = aOldScope->GetWrappedNativeMap(); + Native2WrappedNativeMap* newMap = aNewScope->GetWrappedNativeMap(); + XPCAutoLock lock(aOldScope->GetRuntime()->GetMapLock()); + + oldMap->Remove(wrapper); + + if (wrapper->HasProto()) + wrapper->SetProto(newProto); + + // If the wrapper has no scriptable or it has a non-shared + // scriptable, then we don't need to mess with it. + // Otherwise... + + if (wrapper->mScriptableInfo && + wrapper->mScriptableInfo == oldProto->GetScriptableInfo()) { + // The new proto had better have the same JSClass stuff as + // the old one! We maintain a runtime wide unique map of + // this stuff. So, if these don't match then the caller is + // doing something bad here. + + NS_ASSERTION(oldProto->GetScriptableInfo()->GetScriptableShared() == + newProto->GetScriptableInfo()->GetScriptableShared(), + "Changing proto is also changing JSObject Classname or " + "helper's nsIXPScriptable flags. This is not allowed!"); + + wrapper->UpdateScriptableInfo(newProto->GetScriptableInfo()); } - // Before proceeding, eagerly create any same-compartment security wrappers - // that the object might have. This forces us to take the 'WithWrapper' path - // while transplanting that handles this stuff correctly. - { - JSAutoCompartment innerAC(cx, aOldScope->GetGlobalJSObject()); - if (!wrapper->GetSameCompartmentSecurityWrapper(cx)) - return NS_ERROR_FAILURE; - } - - // Update scope maps. This section modifies global state, so from - // here on out we crash if anything fails. - { // scoped lock - Native2WrappedNativeMap* oldMap = aOldScope->GetWrappedNativeMap(); - Native2WrappedNativeMap* newMap = aNewScope->GetWrappedNativeMap(); - XPCAutoLock lock(aOldScope->GetRuntime()->GetMapLock()); - - oldMap->Remove(wrapper); - - if (wrapper->HasProto()) - wrapper->SetProto(newProto); - - // If the wrapper has no scriptable or it has a non-shared - // scriptable, then we don't need to mess with it. - // Otherwise... - - if (wrapper->mScriptableInfo && - wrapper->mScriptableInfo == oldProto->GetScriptableInfo()) { - // The new proto had better have the same JSClass stuff as - // the old one! We maintain a runtime wide unique map of - // this stuff. So, if these don't match then the caller is - // doing something bad here. - - NS_ASSERTION(oldProto->GetScriptableInfo()->GetScriptableShared() == - newProto->GetScriptableInfo()->GetScriptableShared(), - "Changing proto is also changing JSObject Classname or " - "helper's nsIXPScriptable flags. This is not allowed!"); - - wrapper->UpdateScriptableInfo(newProto->GetScriptableInfo()); - } - - // Crash if the wrapper is already in the new scope. - if (newMap->Find(wrapper->GetIdentityObject())) - MOZ_CRASH(); - - if (!newMap->Add(wrapper)) - MOZ_CRASH(); - } - - JSObject *ww = wrapper->GetWrapper(); - if (ww) { - JSObject *newwrapper; - MOZ_ASSERT(wrapper->NeedsSOW(), "weird wrapper wrapper"); - newwrapper = xpc::WrapperFactory::WrapSOWObject(cx, newobj); - if (!newwrapper) - MOZ_CRASH(); - - // Ok, now we do the special object-plus-wrapper transplant. - ww = xpc::TransplantObjectWithWrapper(cx, flat, ww, newobj, - newwrapper); - if (!ww) - MOZ_CRASH(); - - flat = newobj; - wrapper->SetWrapper(ww); - } else { - flat = xpc::TransplantObject(cx, flat, newobj); - if (!flat) - MOZ_CRASH(); - } - - wrapper->mFlatJSObject = flat; - if (cache) { - bool preserving = cache->PreservingWrapper(); - cache->SetPreservingWrapper(false); - cache->SetWrapper(flat); - cache->SetPreservingWrapper(preserving); - } - if (!JS_CopyPropertiesFrom(cx, flat, propertyHolder)) + // Crash if the wrapper is already in the new scope. + if (newMap->Find(wrapper->GetIdentityObject())) MOZ_CRASH(); + if (!newMap->Add(wrapper)) + MOZ_CRASH(); + } + + JSObject *ww = wrapper->GetWrapper(); + if (ww) { + JSObject *newwrapper; + MOZ_ASSERT(wrapper->NeedsSOW(), "weird wrapper wrapper"); + newwrapper = xpc::WrapperFactory::WrapSOWObject(cx, newobj); + if (!newwrapper) + MOZ_CRASH(); + + // Ok, now we do the special object-plus-wrapper transplant. + ww = xpc::TransplantObjectWithWrapper(cx, flat, ww, newobj, + newwrapper); + if (!ww) + MOZ_CRASH(); + + flat = newobj; + wrapper->SetWrapper(ww); + } else { + flat = xpc::TransplantObject(cx, flat, newobj); + if (!flat) + MOZ_CRASH(); + } + + wrapper->mFlatJSObject = flat; + if (cache) { + bool preserving = cache->PreservingWrapper(); + cache->SetPreservingWrapper(false); + cache->SetWrapper(flat); + cache->SetPreservingWrapper(preserving); + } + if (!JS_CopyPropertiesFrom(cx, flat, propertyHolder)) + MOZ_CRASH(); + // Call the scriptable hook to indicate that we transplanted. XPCNativeScriptableInfo* si = wrapper->GetScriptableInfo(); if (si->GetFlags().WantPostCreate()) From 08d68069d596ce00e96fcdf280716d8ef7509ea2 Mon Sep 17 00:00:00 2001 From: Peter Van der Beken Date: Fri, 19 Apr 2013 21:58:30 +0200 Subject: [PATCH 23/84] Bug 851465 - Remove slim wrappers - remove slim wrapper macros and rename WN macros. r=bholley. --- caps/src/nsScriptSecurityManager.cpp | 2 +- dom/base/nsDOMClassInfo.cpp | 2 +- js/xpconnect/src/XPCCallContext.cpp | 5 ++- js/xpconnect/src/XPCComponents.cpp | 2 +- js/xpconnect/src/XPCConvert.cpp | 11 +++--- js/xpconnect/src/XPCJSID.cpp | 10 +++--- js/xpconnect/src/XPCJSRuntime.cpp | 2 +- js/xpconnect/src/XPCQuickStubs.cpp | 8 ++--- js/xpconnect/src/XPCVariant.cpp | 2 +- js/xpconnect/src/XPCWrappedJSClass.cpp | 3 +- js/xpconnect/src/XPCWrappedNative.cpp | 14 +++----- js/xpconnect/src/XPCWrappedNativeJSOps.cpp | 6 ++-- js/xpconnect/src/nsXPConnect.cpp | 39 ++++++++++------------ js/xpconnect/src/xpcprivate.h | 19 +++-------- js/xpconnect/src/xpcpublic.h | 34 ++++--------------- js/xpconnect/wrappers/AccessCheck.cpp | 6 ++-- js/xpconnect/wrappers/WrapperFactory.cpp | 6 ++-- js/xpconnect/wrappers/XrayWrapper.cpp | 4 +-- 18 files changed, 66 insertions(+), 109 deletions(-) diff --git a/caps/src/nsScriptSecurityManager.cpp b/caps/src/nsScriptSecurityManager.cpp index 92a7f03c8737..9e7d704cf472 100644 --- a/caps/src/nsScriptSecurityManager.cpp +++ b/caps/src/nsScriptSecurityManager.cpp @@ -2090,7 +2090,7 @@ nsScriptSecurityManager::old_doGetObjectPrincipal(JS::Handle aObj, // Note: jsClass is set before this loop, and also at the // *end* of this loop. - if (IS_WRAPPER_CLASS(jsClass)) { + if (IS_WN_CLASS(jsClass)) { result = nsXPConnect::XPConnect()->GetPrincipal(obj, aAllowShortCircuit); if (result) { diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index 045612ec173c..d6cc34708dd5 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -4259,7 +4259,7 @@ LocationSetterGuts(JSContext *cx, JSObject *obj, jsval *vp) { // This function duplicates some of the logic in XPC_WN_HelperSetProperty obj = js::CheckedUnwrap(obj, /* stopAtOuter = */ false); - if (!IS_WN_WRAPPER(obj)) + if (!IS_WN_REFLECTOR(obj)) return NS_ERROR_XPC_BAD_CONVERT_JS; XPCWrappedNative *wrapper = XPCWrappedNative::Get(obj); diff --git a/js/xpconnect/src/XPCCallContext.cpp b/js/xpconnect/src/XPCCallContext.cpp index 41f67570e8a1..44b3d0c0a705 100644 --- a/js/xpconnect/src/XPCCallContext.cpp +++ b/js/xpconnect/src/XPCCallContext.cpp @@ -98,7 +98,7 @@ XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage, } } else { js::Class *clasp = js::GetObjectClass(unwrapped); - if (IS_WRAPPER_CLASS(clasp)) { + if (IS_WN_CLASS(clasp)) { mWrapper = XPCWrappedNative::Get(unwrapped); } else if (IS_TEAROFF_CLASS(clasp)) { mTearOff = (XPCWrappedNativeTearOff*)js::GetObjectPrivate(unwrapped); @@ -421,8 +421,7 @@ XPCCallContext::UnwrapThisIfAllowed(HandleObject obj, HandleObject fun, unsigned MOZ_ASSERT(unwrapped == JS_ObjectToInnerObject(mJSContext, js::Wrapper::wrappedObject(obj))); // Make sure we have an XPCWN, and grab it. - MOZ_ASSERT(!IS_SLIM_WRAPPER(unwrapped), "security wrapping morphs slim wrappers"); - if (!IS_WRAPPER_CLASS(js::GetObjectClass(unwrapped))) + if (!IS_WN_REFLECTOR(unwrapped)) return nullptr; XPCWrappedNative *wn = (XPCWrappedNative*)js::GetObjectPrivate(unwrapped); diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp index 602f24424a56..21a477a64624 100644 --- a/js/xpconnect/src/XPCComponents.cpp +++ b/js/xpconnect/src/XPCComponents.cpp @@ -3312,7 +3312,7 @@ xpc_CreateSandboxObject(JSContext *cx, jsval *vp, nsISupports *prinOrSop, Sandbo // Now check what sort of thing we've got in |proto| JSObject *unwrappedProto = js::UncheckedUnwrap(options.proto, false); js::Class *unwrappedClass = js::GetObjectClass(unwrappedProto); - if (IS_WRAPPER_CLASS(unwrappedClass) || + if (IS_WN_CLASS(unwrappedClass) || mozilla::dom::IsDOMClass(Jsvalify(unwrappedClass))) { // Wrap it up in a proxy that will do the right thing in terms // of this-binding for methods. diff --git a/js/xpconnect/src/XPCConvert.cpp b/js/xpconnect/src/XPCConvert.cpp index c20fd223ceba..f1ce4953544e 100644 --- a/js/xpconnect/src/XPCConvert.cpp +++ b/js/xpconnect/src/XPCConvert.cpp @@ -862,8 +862,7 @@ XPCConvert::NativeInterface2JSObject(jsval* d, } } - NS_ASSERTION(!flat || IS_WRAPPER_CLASS(js::GetObjectClass(flat)), - "What kind of wrapper is this?"); + NS_ASSERTION(!flat || IS_WN_REFLECTOR(flat), "What kind of wrapper is this?"); nsresult rv; XPCWrappedNative* wrapper; @@ -874,7 +873,7 @@ XPCConvert::NativeInterface2JSObject(jsval* d, wrapper = strongWrapper; } else { - MOZ_ASSERT(IS_WN_WRAPPER_OBJECT(flat)); + MOZ_ASSERT(IS_WN_REFLECTOR(flat)); wrapper = static_cast(xpc_GetJSPrivate(flat)); @@ -985,7 +984,7 @@ XPCConvert::JSObject2NativeInterface(void** dest, HandleObject src, // Is this really a native xpcom object with a wrapper? XPCWrappedNative* wrappedNative = nullptr; - if (IS_WN_WRAPPER(inner)) + if (IS_WN_REFLECTOR(inner)) wrappedNative = XPCWrappedNative::Get(inner); if (wrappedNative) { iface = wrappedNative->GetIdentityObject(); @@ -1116,8 +1115,8 @@ XPCConvert::JSValToXPCException(jsval sArg, JSObject *unwrapped = js::CheckedUnwrap(obj, /* stopAtOuter = */ false); if (!unwrapped) return NS_ERROR_XPC_SECURITY_MANAGER_VETO; - XPCWrappedNative* wrapper = IS_WN_WRAPPER(unwrapped) ? XPCWrappedNative::Get(unwrapped) - : nullptr; + XPCWrappedNative* wrapper = IS_WN_REFLECTOR(unwrapped) ? XPCWrappedNative::Get(unwrapped) + : nullptr; if (wrapper) { nsISupports* supports = wrapper->GetIdentityObject(); nsCOMPtr iface = do_QueryInterface(supports); diff --git a/js/xpconnect/src/XPCJSID.cpp b/js/xpconnect/src/XPCJSID.cpp index 1628d9a38d41..8c7d59807fda 100644 --- a/js/xpconnect/src/XPCJSID.cpp +++ b/js/xpconnect/src/XPCJSID.cpp @@ -476,7 +476,7 @@ static JSObject * FindObjectForHasInstance(JSContext *cx, HandleObject objArg) { RootedObject obj(cx, objArg), proto(cx); - while (obj && !IS_WRAPPER_CLASS(js::GetObjectClass(obj)) && !IsDOMObject(obj)) { + while (obj && !IS_WN_REFLECTOR(obj) && !IsDOMObject(obj)) { if (js::IsWrapper(obj)) { obj = js::CheckedUnwrap(obj, /* stopAtOuter = */ false); continue; @@ -524,7 +524,7 @@ nsJSIID::HasInstance(nsIXPConnectWrappedNative *wrapper, return NS_OK; } - MOZ_ASSERT(IS_WN_WRAPPER(obj)); + MOZ_ASSERT(IS_WN_REFLECTOR(obj)); XPCWrappedNative* other_wrapper = XPCWrappedNative::Get(obj); if (!other_wrapper) return NS_OK; @@ -841,7 +841,7 @@ nsJSCID::HasInstance(nsIXPConnectWrappedNative *wrapper, // is this really a native xpcom object with a wrapper? nsIClassInfo* ci = nullptr; obj = FindObjectForHasInstance(cx, obj); - if (!obj || !IS_WRAPPER_CLASS(js::GetObjectClass(obj))) + if (!obj || !IS_WN_REFLECTOR(obj)) return rv; if (XPCWrappedNative* other_wrapper = XPCWrappedNative::Get(obj)) ci = other_wrapper->GetClassInfo(); @@ -893,7 +893,7 @@ xpc_JSObjectToID(JSContext *cx, JSObject* obj) // NOTE: this call does NOT addref XPCWrappedNative* wrapper = nullptr; obj = js::CheckedUnwrap(obj); - if (obj && IS_WN_WRAPPER(obj)) + if (obj && IS_WN_REFLECTOR(obj)) wrapper = XPCWrappedNative::Get(obj); if (wrapper && (wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSID)) || @@ -911,7 +911,7 @@ xpc_JSObjectIsID(JSContext *cx, JSObject* obj) // NOTE: this call does NOT addref XPCWrappedNative* wrapper = nullptr; obj = js::CheckedUnwrap(obj); - if (obj && IS_WN_WRAPPER(obj)) + if (obj && IS_WN_REFLECTOR(obj)) wrapper = XPCWrappedNative::Get(obj); return wrapper && (wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSID)) || diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index 5f9118467bf3..4b83e0fe56ed 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -2537,7 +2537,7 @@ PreserveWrapper(JSContext *cx, JSObject *objArg) if (!ccx.IsValid()) return false; - if (!IS_WRAPPER_CLASS(js::GetObjectClass(obj))) + if (!IS_WN_REFLECTOR(obj)) return mozilla::dom::TryPreserveWrapper(obj); nsISupports *supports = XPCWrappedNative::Get(obj)->Native(); diff --git a/js/xpconnect/src/XPCQuickStubs.cpp b/js/xpconnect/src/XPCQuickStubs.cpp index 315ed19498e3..4599e9be9397 100644 --- a/js/xpconnect/src/XPCQuickStubs.cpp +++ b/js/xpconnect/src/XPCQuickStubs.cpp @@ -69,7 +69,7 @@ LookupInterfaceOrAncestor(uint32_t tableSize, const xpc_qsHashEntry *table, static MOZ_ALWAYS_INLINE bool HasBitInInterfacesBitmap(JSObject *obj, uint32_t interfaceBit) { - NS_ASSERTION(IS_WRAPPER_CLASS(js::GetObjectClass(obj)), "Not a wrapper?"); + NS_ASSERTION(IS_WN_REFLECTOR(obj), "Not a wrapper?"); XPCWrappedNativeJSClass *clasp = (XPCWrappedNativeJSClass*)js::GetObjectClass(obj); @@ -178,7 +178,7 @@ GetMemberInfo(JSObject *obj, jsid memberId, const char **ifaceName) // because it isn't worth the risk of something going wrong just to generate // an error message. Instead, only handle the simple case where we have the // reflector in hand. - if (IS_WRAPPER_CLASS(js::GetObjectClass(obj))) { + if (IS_WN_REFLECTOR(obj)) { XPCWrappedNative *wrapper = static_cast(js::GetObjectPrivate(obj)); XPCWrappedNativeProto *proto = wrapper->GetProto(); @@ -561,7 +561,7 @@ getWrapper(JSContext *cx, // If we've got a WN, store things the way callers expect. Otherwise, leave // things null and return. - if (IS_WRAPPER_CLASS(clasp)) + if (IS_WN_CLASS(clasp)) *wrapper = XPCWrappedNative::Get(obj); return NS_OK; @@ -614,7 +614,7 @@ castNativeFromWrapper(JSContext *cx, XPCWrappedNativeTearOff *tearoff; JSObject *cur; - if (IS_WRAPPER_CLASS(js::GetObjectClass(obj))) { + if (IS_WN_REFLECTOR(obj)) { cur = obj; wrapper = (XPCWrappedNative*)xpc_GetJSPrivate(obj); tearoff = nullptr; diff --git a/js/xpconnect/src/XPCVariant.cpp b/js/xpconnect/src/XPCVariant.cpp index 25de5166df89..814aa52c80e3 100644 --- a/js/xpconnect/src/XPCVariant.cpp +++ b/js/xpconnect/src/XPCVariant.cpp @@ -45,7 +45,7 @@ XPCVariant::XPCVariant(JSContext* cx, jsval aJSVal) mJSVal = OBJECT_TO_JSVAL(obj); JSObject *unwrapped = js::CheckedUnwrap(obj, /* stopAtOuter = */ false); - mReturnRawObject = !(unwrapped && IS_WN_WRAPPER(unwrapped)); + mReturnRawObject = !(unwrapped && IS_WN_REFLECTOR(unwrapped)); } else mReturnRawObject = false; } diff --git a/js/xpconnect/src/XPCWrappedJSClass.cpp b/js/xpconnect/src/XPCWrappedJSClass.cpp index 54f8afb19cbd..21588f80ce03 100644 --- a/js/xpconnect/src/XPCWrappedJSClass.cpp +++ b/js/xpconnect/src/XPCWrappedJSClass.cpp @@ -699,8 +699,7 @@ nsXPCWrappedJSClass::DelegatedQueryInterface(nsXPCWrappedJS* self, bool isSystem; rv = secMan->IsSystemPrincipal(objPrin, &isSystem); - if ((NS_FAILED(rv) || !isSystem) && - !IS_WRAPPER_CLASS(js::GetObjectClass(selfObj))) { + if ((NS_FAILED(rv) || !isSystem) && !IS_WN_REFLECTOR(selfObj)) { // A content object. nsRefPtr checked = new SameOriginCheckedComponent(self); diff --git a/js/xpconnect/src/XPCWrappedNative.cpp b/js/xpconnect/src/XPCWrappedNative.cpp index 49abed097bec..05ce11a10949 100644 --- a/js/xpconnect/src/XPCWrappedNative.cpp +++ b/js/xpconnect/src/XPCWrappedNative.cpp @@ -36,7 +36,7 @@ bool xpc_OkToHandOutWrapper(nsWrapperCache *cache) { NS_ABORT_IF_FALSE(cache->GetWrapper(), "Must have wrapper"); - NS_ABORT_IF_FALSE(IS_WN_WRAPPER(cache->GetWrapper()), + NS_ABORT_IF_FALSE(IS_WN_REFLECTOR(cache->GetWrapper()), "Must have XPCWrappedNative wrapper"); return !static_cast(xpc_GetJSPrivate(cache->GetWrapper()))-> @@ -1358,10 +1358,8 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCWrappedNativeScope* aOldScope, js::GetObjectCompartment(aNewScope->GetGlobalJSObject())); NS_ASSERTION(aNewParent, "won't be able to find the new parent"); - if (wrapper->HasProto()) + if (wrapper->HasProto()) { oldProto = wrapper->GetProto(); - - if (oldProto) { XPCNativeScriptableInfo *info = oldProto->GetScriptableInfo(); XPCNativeScriptableCreateInfo ci(*info); newProto = @@ -1509,10 +1507,8 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCWrappedNativeScope* aOldScope, if (!JS_SetParent(cx, flat, aNewParent)) MOZ_CRASH(); - JSObject *nw; - if (wrapper && - (nw = wrapper->GetWrapper()) && - !JS_SetParent(cx, nw, JS_GetGlobalForObject(cx, aNewParent))) { + JSObject *nw = wrapper->GetWrapper(); + if (nw && !JS_SetParent(cx, nw, JS_GetGlobalForObject(cx, aNewParent))) { MOZ_CRASH(); } } @@ -1560,7 +1556,7 @@ RescueOrphans(HandleObject obj) // PreCreate may touch dead compartments. js::AutoMaybeTouchDeadZones agc(parentObj); - bool isWN = IS_WRAPPER_CLASS(js::GetObjectClass(obj)); + bool isWN = IS_WN_REFLECTOR(obj); // There's one little nasty twist here. For reasons described in bug 752764, // we nuke SOW-ed objects after transplanting them. This means that nodes diff --git a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp index 99aa28d91435..f038a9677ea9 100644 --- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp +++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp @@ -610,7 +610,7 @@ MarkWrappedNative(JSTracer *trc, JSObject *obj) if (clazz->flags & JSCLASS_DOM_GLOBAL) { mozilla::dom::TraceProtoAndIfaceCache(trc, obj); } - MOZ_ASSERT(IS_WRAPPER_CLASS(clazz)); + MOZ_ASSERT(IS_WN_CLASS(clazz)); XPCWrappedNative *wrapper = XPCWrappedNative::Get(obj); if (wrapper && wrapper->IsValid()) @@ -795,7 +795,7 @@ XPC_WN_MaybeResolvingDeletePropertyStub(JSContext *cx, JSHandleObject obj, JSHan JS_ReportError(cx, "Permission denied to operate on object."); \ return false; \ } \ - if (!IS_WRAPPER_CLASS(js::GetObjectClass(unwrapped))) { \ + if (!IS_WN_REFLECTOR(unwrapped)) { \ return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); \ } \ XPCWrappedNative *wrapper = XPCWrappedNative::Get(unwrapped); \ @@ -1038,7 +1038,7 @@ XPC_WN_JSOp_Enumerate(JSContext *cx, JSHandleObject obj, JSIterateOp enum_op, JSMutableHandleValue statep, MutableHandleId idp) { js::Class *clazz = js::GetObjectClass(obj); - if (!IS_WRAPPER_CLASS(clazz) || clazz == &XPC_WN_NoHelper_JSClass.base) { + if (!IS_WN_CLASS(clazz) || clazz == &XPC_WN_NoHelper_JSClass.base) { // obj must be a prototype object or a wrapper w/o a // helper. Short circuit this call to the default // implementation. diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index b13d5bb90059..393f37c6bd45 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -1222,7 +1222,7 @@ nsXPConnect::GetWrappedNativeOfJSObject(JSContext * aJSContext, RootedObject aJSObj(aJSContext, aJSObjArg); aJSObj = js::CheckedUnwrap(aJSObj, /* stopAtOuter = */ false); - if (aJSObj && IS_WN_WRAPPER(aJSObj)) { + if (aJSObj && IS_WN_REFLECTOR(aJSObj)) { NS_IF_ADDREF(*_retval = XPCWrappedNative::Get(aJSObj)); return NS_OK; } @@ -1245,7 +1245,7 @@ nsXPConnect::GetNativeOfWrapper(JSContext * aJSContext, JS_ReportError(aJSContext, "Permission denied to get native of security wrapper"); return nullptr; } - if (IS_WRAPPER_CLASS(js::GetObjectClass(aJSObj))) { + if (IS_WN_REFLECTOR(aJSObj)) { if (XPCWrappedNative *wn = XPCWrappedNative::Get(aJSObj)) return wn->Native(); return nullptr; @@ -1918,28 +1918,25 @@ IsJSContextOnStack(JSContext *aCx) nsIPrincipal* nsXPConnect::GetPrincipal(JSObject* obj, bool allowShortCircuit) const { - NS_ASSERTION(IS_WRAPPER_CLASS(js::GetObjectClass(obj)), - "What kind of wrapper is this?"); + NS_ASSERTION(IS_WN_REFLECTOR(obj), "What kind of wrapper is this?"); - if (IS_WN_WRAPPER_OBJECT(obj)) { - XPCWrappedNative *xpcWrapper = - (XPCWrappedNative *)xpc_GetJSPrivate(obj); - if (xpcWrapper) { - if (allowShortCircuit) { - nsIPrincipal *result = xpcWrapper->GetObjectPrincipal(); - if (result) { - return result; - } + XPCWrappedNative *xpcWrapper = + (XPCWrappedNative *)xpc_GetJSPrivate(obj); + if (xpcWrapper) { + if (allowShortCircuit) { + nsIPrincipal *result = xpcWrapper->GetObjectPrincipal(); + if (result) { + return result; } + } - // If not, check if it points to an nsIScriptObjectPrincipal - nsCOMPtr objPrin = - do_QueryInterface(xpcWrapper->Native()); - if (objPrin) { - nsIPrincipal *result = objPrin->GetPrincipal(); - if (result) { - return result; - } + // If not, check if it points to an nsIScriptObjectPrincipal + nsCOMPtr objPrin = + do_QueryInterface(xpcWrapper->Native()); + if (objPrin) { + nsIPrincipal *result = objPrin->GetPrincipal(); + if (result) { + return result; } } } diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 8722472ae9ff..68e5dff2c17f 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -42,10 +42,6 @@ * pointers are smooshed together in a tagged union.) Either way it can reach * its scope. * - * In the case of slim wrappers (where there is no XPCWrappedNative), the - * flattened JS object has a pointer to the XPCWrappedNativeProto stored in a - * reserved slot. - * * An XPCWrappedNativeProto keeps track of the set of interfaces implemented by * the C++ object in an XPCNativeSet. (The list of interfaces is obtained by * calling a method on the nsIClassInfo.) An XPCNativeSet is a collection of @@ -287,13 +283,13 @@ extern const char XPC_XPCONNECT_CONTRACTID[]; inline void SetWNExpandoChain(JSObject *obj, JSObject *chain) { - MOZ_ASSERT(IS_WN_WRAPPER(obj)); + MOZ_ASSERT(IS_WN_REFLECTOR(obj)); JS_SetReservedSlot(obj, WRAPPER_MULTISLOT, JS::ObjectOrNullValue(chain)); } inline JSObject* GetWNExpandoChain(JSObject *obj) { - MOZ_ASSERT(IS_WN_WRAPPER(obj)); + MOZ_ASSERT(IS_WN_REFLECTOR(obj)); return JS_GetReservedSlot(obj, WRAPPER_MULTISLOT).toObjectOrNull(); } @@ -1937,13 +1933,10 @@ public: {return mJSClass.interfacesBitmap;} JSClass* GetJSClass() {return Jsvalify(&mJSClass.base);} - JSClass* GetSlimJSClass() - {if (mCanBeSlim) return GetJSClass(); return nullptr;} XPCNativeScriptableShared(uint32_t aFlags, char* aName, uint32_t interfacesBitmap) - : mFlags(aFlags), - mCanBeSlim(false) + : mFlags(aFlags) {memset(&mJSClass, 0, sizeof(mJSClass)); mJSClass.base.name = aName; // take ownership mJSClass.interfacesBitmap = interfacesBitmap; @@ -1966,7 +1959,6 @@ public: private: XPCNativeScriptableFlags mFlags; XPCWrappedNativeJSClass mJSClass; - JSBool mCanBeSlim; }; /***************************************************************************/ @@ -1991,9 +1983,6 @@ public: JSClass* GetJSClass() {return mShared->GetJSClass();} - JSClass* - GetSlimJSClass() {return mShared->GetSlimJSClass();} - XPCNativeScriptableShared* GetScriptableShared() {return mShared;} @@ -2398,7 +2387,7 @@ public: SetSet(XPCNativeSet* set) {XPCAutoLock al(GetLock()); mSet = set;} static XPCWrappedNative* Get(JSObject *obj) { - MOZ_ASSERT(IS_WN_WRAPPER(obj)); + MOZ_ASSERT(IS_WN_REFLECTOR(obj)); return (XPCWrappedNative*)js::GetObjectPrivate(obj); } diff --git a/js/xpconnect/src/xpcpublic.h b/js/xpconnect/src/xpcpublic.h index 6b9fd1af0759..c8b4f1959f50 100644 --- a/js/xpconnect/src/xpcpublic.h +++ b/js/xpconnect/src/xpcpublic.h @@ -82,45 +82,23 @@ xpc_LocalizeRuntime(JSRuntime *rt); NS_EXPORT_(void) xpc_DelocalizeRuntime(JSRuntime *rt); -static inline bool IS_WRAPPER_CLASS(js::Class* clazz) +// If IS_WN_CLASS for the JSClass of an object is true, the object is a +// wrappednative wrapper, holding the XPCWrappedNative in its private slot. + +static inline bool IS_WN_CLASS(js::Class* clazz) { return clazz->ext.isWrappedNative; } -// If IS_WRAPPER_CLASS for the JSClass of an object is true, the object can be -// a slim wrapper, holding a native in its private slot, or a wrappednative -// wrapper, holding the XPCWrappedNative in its private slot. A slim wrapper -// also holds a pointer to its XPCWrappedNativeProto in a reserved slot, we can -// check that slot for a private value (i.e. a double) to distinguish between -// the two. This allows us to store a JSObject in that slot for non-slim wrappers -// while still being able to distinguish the two cases. - // NB: This slot isn't actually reserved for us on globals, because SpiderMonkey // uses the first N slots on globals internally. The fact that we use it for // wrapped global objects is totally broken. But due to a happy coincidence, the // JS engine never uses that slot. This still needs fixing though. See bug 760095. #define WRAPPER_MULTISLOT 0 -static inline bool IS_WN_WRAPPER_OBJECT(JSObject *obj) +static inline bool IS_WN_REFLECTOR(JSObject *obj) { - MOZ_ASSERT(IS_WRAPPER_CLASS(js::GetObjectClass(obj))); - return !js::GetReservedSlot(obj, WRAPPER_MULTISLOT).isDouble(); -} -static inline bool IS_SLIM_WRAPPER_OBJECT(JSObject *obj) -{ - return !IS_WN_WRAPPER_OBJECT(obj); -} - -// Use these functions if IS_WRAPPER_CLASS(GetObjectClass(obj)) might be false. -// Avoid calling them if IS_WRAPPER_CLASS(GetObjectClass(obj)) can only be -// true, as we'd do a redundant call to IS_WRAPPER_CLASS. -static inline bool IS_WN_WRAPPER(JSObject *obj) -{ - return IS_WRAPPER_CLASS(js::GetObjectClass(obj)) && IS_WN_WRAPPER_OBJECT(obj); -} -static inline bool IS_SLIM_WRAPPER(JSObject *obj) -{ - return IS_WRAPPER_CLASS(js::GetObjectClass(obj)) && IS_SLIM_WRAPPER_OBJECT(obj); + return IS_WN_CLASS(js::GetObjectClass(obj)); } extern bool diff --git a/js/xpconnect/wrappers/AccessCheck.cpp b/js/xpconnect/wrappers/AccessCheck.cpp index be79dc31365a..0467e86a5fbd 100644 --- a/js/xpconnect/wrappers/AccessCheck.cpp +++ b/js/xpconnect/wrappers/AccessCheck.cpp @@ -179,8 +179,8 @@ IsFrameId(JSContext *cx, JSObject *objArg, jsid idArg) obj = JS_ObjectToInnerObject(cx, obj); MOZ_ASSERT(!js::IsWrapper(obj)); - XPCWrappedNative *wn = IS_WN_WRAPPER(obj) ? XPCWrappedNative::Get(obj) - : nullptr; + XPCWrappedNative *wn = IS_WN_REFLECTOR(obj) ? XPCWrappedNative::Get(obj) + : nullptr; if (!wn) { return false; } @@ -272,7 +272,7 @@ AccessCheck::needsSystemOnlyWrapper(JSObject *obj) if (dom::GetSameCompartmentWrapperForDOMBinding(wrapper)) return wrapper != obj; - if (!IS_WN_WRAPPER(obj)) + if (!IS_WN_REFLECTOR(obj)) return false; XPCWrappedNative *wn = static_cast(js::GetObjectPrivate(obj)); diff --git a/js/xpconnect/wrappers/WrapperFactory.cpp b/js/xpconnect/wrappers/WrapperFactory.cpp index 060f9511b0ab..1a0a9406754a 100644 --- a/js/xpconnect/wrappers/WrapperFactory.cpp +++ b/js/xpconnect/wrappers/WrapperFactory.cpp @@ -196,7 +196,7 @@ WrapperFactory::PrepareForWrapping(JSContext *cx, HandleObject scope, // those objects in a security wrapper, then we need to hand back the // wrapper for the new scope instead. Also, global objects don't move // between scopes so for those we also want to return the wrapper. So... - if (!IS_WN_WRAPPER(obj) || !js::GetObjectParent(obj)) + if (!IS_WN_REFLECTOR(obj) || !js::GetObjectParent(obj)) return DoubleWrap(cx, obj, flags); XPCWrappedNative *wn = static_cast(xpc_GetJSPrivate(obj)); @@ -295,7 +295,7 @@ WrapperFactory::PrepareForWrapping(JSContext *cx, HandleObject scope, NS_ENSURE_SUCCESS(rv, nullptr); obj = JSVAL_TO_OBJECT(v); - NS_ASSERTION(IS_WN_WRAPPER(obj), "bad object"); + NS_ASSERTION(IS_WN_REFLECTOR(obj), "bad object"); // Because the underlying native didn't have a PreCreate hook, we had // to a new (or possibly pre-existing) XPCWN in our compartment. @@ -517,7 +517,7 @@ WrapperFactory::WrapForSameCompartment(JSContext *cx, HandleObject objArg) MOZ_ASSERT(!dom::IsDOMObject(obj)); - if (!IS_WN_WRAPPER(obj)) + if (!IS_WN_REFLECTOR(obj)) return obj; // Extract the WN. It should exist. diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index 070c50f8d7bf..5efceda74bb5 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -61,7 +61,7 @@ GetXrayType(JSObject *obj) return XrayForDOMObject; js::Class* clasp = js::GetObjectClass(obj); - if (IS_WRAPPER_CLASS(clasp) || clasp->ext.innerObject) + if (IS_WN_CLASS(clasp) || clasp->ext.innerObject) return XrayForWrappedNative; return NotXray; @@ -509,7 +509,7 @@ GetHolder(JSObject *obj) static XPCWrappedNative * GetWrappedNative(JSObject *obj) { - MOZ_ASSERT(IS_WN_WRAPPER_OBJECT(obj)); + MOZ_ASSERT(IS_WN_REFLECTOR(obj)); return static_cast(js::GetObjectPrivate(obj)); } From 6ba9bc75aca1d421b52c630e0de2f1f46059c8a0 Mon Sep 17 00:00:00 2001 From: Peter Van der Beken Date: Thu, 13 Jun 2013 16:55:40 +0200 Subject: [PATCH 24/84] Bug 851465 - Remove slim wrappers - rename WRAPPER_MULTISLOT. r=bholley. --- js/xpconnect/src/XPCWrappedNative.cpp | 5 +++-- js/xpconnect/src/xpcprivate.h | 12 ++++++++---- js/xpconnect/src/xpcpublic.h | 7 ------- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/js/xpconnect/src/XPCWrappedNative.cpp b/js/xpconnect/src/XPCWrappedNative.cpp index 05ce11a10949..4b60dd7c8677 100644 --- a/js/xpconnect/src/XPCWrappedNative.cpp +++ b/js/xpconnect/src/XPCWrappedNative.cpp @@ -1056,8 +1056,9 @@ XPCWrappedNative::FinishInit() { AutoJSContext cx; - // For all WNs, we want to make sure that the multislot starts out as null. - JS_SetReservedSlot(mFlatJSObject, WRAPPER_MULTISLOT, JSVAL_NULL); + // For all WNs, we want to make sure that the expando chain slot starts out + // as null. + JS_SetReservedSlot(mFlatJSObject, WN_XRAYEXPANDOCHAIN_SLOT, JSVAL_NULL); // This reference will be released when mFlatJSObject is finalized. // Since this reference will push the refcount to 2 it will also root diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 68e5dff2c17f..8651cce43af5 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -277,20 +277,24 @@ extern const char XPC_XPCONNECT_CONTRACTID[]; #define WRAPPER_SLOTS (JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | \ JSCLASS_HAS_RESERVED_SLOTS(1)) -// WRAPPER_MULTISLOT is defined in xpcpublic.h - #define INVALID_OBJECT ((JSObject *)1) +// NB: This slot isn't actually reserved for us on globals, because SpiderMonkey +// uses the first N slots on globals internally. The fact that we use it for +// wrapped global objects is totally broken. But due to a happy coincidence, the +// JS engine never uses that slot. This still needs fixing though. See bug 760095. +#define WN_XRAYEXPANDOCHAIN_SLOT 0 + inline void SetWNExpandoChain(JSObject *obj, JSObject *chain) { MOZ_ASSERT(IS_WN_REFLECTOR(obj)); - JS_SetReservedSlot(obj, WRAPPER_MULTISLOT, JS::ObjectOrNullValue(chain)); + JS_SetReservedSlot(obj, WN_XRAYEXPANDOCHAIN_SLOT, JS::ObjectOrNullValue(chain)); } inline JSObject* GetWNExpandoChain(JSObject *obj) { MOZ_ASSERT(IS_WN_REFLECTOR(obj)); - return JS_GetReservedSlot(obj, WRAPPER_MULTISLOT).toObjectOrNull(); + return JS_GetReservedSlot(obj, WN_XRAYEXPANDOCHAIN_SLOT).toObjectOrNull(); } /***************************************************************************/ diff --git a/js/xpconnect/src/xpcpublic.h b/js/xpconnect/src/xpcpublic.h index c8b4f1959f50..6d3e5e6cc7ea 100644 --- a/js/xpconnect/src/xpcpublic.h +++ b/js/xpconnect/src/xpcpublic.h @@ -89,13 +89,6 @@ static inline bool IS_WN_CLASS(js::Class* clazz) { return clazz->ext.isWrappedNative; } - -// NB: This slot isn't actually reserved for us on globals, because SpiderMonkey -// uses the first N slots on globals internally. The fact that we use it for -// wrapped global objects is totally broken. But due to a happy coincidence, the -// JS engine never uses that slot. This still needs fixing though. See bug 760095. -#define WRAPPER_MULTISLOT 0 - static inline bool IS_WN_REFLECTOR(JSObject *obj) { return IS_WN_CLASS(js::GetObjectClass(obj)); From 34a5b4b51993cc06c4022b5bbff9a09ee6a29981 Mon Sep 17 00:00:00 2001 From: Heather Arthur Date: Thu, 13 Jun 2013 13:56:36 -0700 Subject: [PATCH 25/84] Bug 881633 - Style Editor should remember last selected stylesheet and line when page is reloaded; r=paul --- .../devtools/styleeditor/StyleEditorPanel.jsm | 6 +- .../devtools/styleeditor/StyleEditorUI.jsm | 56 ++++++++--- browser/devtools/styleeditor/test/Makefile.in | 1 + .../test/browser_styleeditor_reload.js | 99 +++++++++++++++++++ 4 files changed, 144 insertions(+), 18 deletions(-) create mode 100644 browser/devtools/styleeditor/test/browser_styleeditor_reload.js diff --git a/browser/devtools/styleeditor/StyleEditorPanel.jsm b/browser/devtools/styleeditor/StyleEditorPanel.jsm index 0cfa54b4e360..783dfe84d9e9 100644 --- a/browser/devtools/styleeditor/StyleEditorPanel.jsm +++ b/browser/devtools/styleeditor/StyleEditorPanel.jsm @@ -91,16 +91,16 @@ StyleEditorPanel.prototype = { * @param {string} href * Url of stylesheet to find and select in editor * @param {number} line - * Line number to jump to after selecting + * Line number to jump to after selecting. One-indexed * @param {number} col - * Column number to jump to after selecting + * Column number to jump to after selecting. One-indexed */ selectStyleSheet: function(href, line, col) { if (!this._debuggee || !this.UI) { return; } let stylesheet = this._debuggee.styleSheetFromHref(href); - this.UI.selectStyleSheet(href, line, col); + this.UI.selectStyleSheet(href, line - 1, col - 1); }, /** diff --git a/browser/devtools/styleeditor/StyleEditorUI.jsm b/browser/devtools/styleeditor/StyleEditorUI.jsm index d89e3c6e7668..3ddca7022cd7 100644 --- a/browser/devtools/styleeditor/StyleEditorUI.jsm +++ b/browser/devtools/styleeditor/StyleEditorUI.jsm @@ -48,7 +48,7 @@ function StyleEditorUI(debuggee, panelDoc) { this._root = this._panelDoc.getElementById("style-editor-chrome"); this.editors = []; - this.selectedStyleSheetIndex = -1; + this.selectedEditor = null; this._onStyleSheetCreated = this._onStyleSheetCreated.bind(this); this._onStyleSheetsCleared = this._onStyleSheetsCleared.bind(this); @@ -84,6 +84,14 @@ StyleEditorUI.prototype = { this._markedDirty = value; }, + /* + * Index of selected stylesheet in document.styleSheets + */ + get selectedStyleSheetIndex() { + return this.selectedEditor ? + this.selectedEditor.styleSheet.styleSheetIndex : -1; + }, + /** * Build the initial UI and wire buttons with event handlers. */ @@ -140,10 +148,17 @@ StyleEditorUI.prototype = { * Handler for debuggee's 'stylesheets-cleared' event. Remove all editors. */ _onStyleSheetsCleared: function() { - this._clearStyleSheetEditors(); + // remember selected sheet and line number for next load + if (this.selectedEditor) { + let href = this.selectedEditor.styleSheet.href; + let {line, col} = this.selectedEditor.sourceEditor.getCaretPosition(); + this.selectStyleSheet(href, line, col); + } + this._clearStyleSheetEditors(); this._view.removeAll(); - this.selectedStyleSheetIndex = -1; + + this.selectedEditor = null; this._root.classList.add("loading"); }, @@ -166,11 +181,22 @@ StyleEditorUI.prototype = { * StyleSheet object for new sheet */ _onDocumentLoad: function(event, styleSheets) { + if (this._styleSheetToSelect) { + // if selected stylesheet from previous load isn't here, + // just set first stylesheet to be selected instead + let selectedExists = styleSheets.some((sheet) => { + return this._styleSheetToSelect.href == sheet.href; + }) + if (!selectedExists) { + this._styleSheetToSelect = null; + } + } for (let sheet of styleSheets) { this._addStyleSheetEditor(sheet); } - // this might be the first stylesheet, so remove loading indicator + this._root.classList.remove("loading"); + this.emit("document-load"); }, @@ -295,13 +321,18 @@ StyleEditorUI.prototype = { onShow: function(summary, details, data) { let editor = data.editor; + this.selectedEditor = editor; + this._styleSheetToSelect = null; + if (!editor.sourceEditor) { // only initialize source editor when we switch to this view let inputElement = details.querySelector(".stylesheet-editor-input"); editor.load(inputElement); } editor.onShow(); - } + + this.emit("editor-selected", editor); + }.bind(this) }); }, @@ -314,7 +345,6 @@ StyleEditorUI.prototype = { for each (let editor in this.editors) { if (editor.styleSheet.href == sheet.href) { this._selectEditor(editor, sheet.line, sheet.col); - this._styleSheetToSelect = null; break; } } @@ -331,18 +361,14 @@ StyleEditorUI.prototype = { * Column number to jump to */ _selectEditor: function(editor, line, col) { - line = line || 1; - col = col || 1; - - this.selectedStyleSheetIndex = editor.styleSheet.styleSheetIndex; + line = line || 0; + col = col || 0; editor.getSourceEditor().then(() => { - editor.sourceEditor.setCaretPosition(line - 1, col - 1); + editor.sourceEditor.setCaretPosition(line, col); }); this._view.activeSummary = editor.summary; - - this.emit("editor-selected", editor); }, /** @@ -354,9 +380,9 @@ StyleEditorUI.prototype = { * a stylesheet is not passed and the editor is initialized we ignore * the call. * @param {Number} [line] - * Line to which the caret should be moved (one-indexed). + * Line to which the caret should be moved (zero-indexed). * @param {Number} [col] - * Column to which the caret should be moved (one-indexed). + * Column to which the caret should be moved (zero-indexed). */ selectStyleSheet: function(href, line, col) { diff --git a/browser/devtools/styleeditor/test/Makefile.in b/browser/devtools/styleeditor/test/Makefile.in index f80625eadb43..c43c941e6409 100644 --- a/browser/devtools/styleeditor/test/Makefile.in +++ b/browser/devtools/styleeditor/test/Makefile.in @@ -28,6 +28,7 @@ _BROWSER_TEST_FILES = \ browser_styleeditor_bug_740541_iframes.js \ browser_styleeditor_bug_851132_middle_click.js \ browser_styleeditor_nostyle.js \ + browser_styleeditor_reload.js \ head.js \ four.html \ head.js \ diff --git a/browser/devtools/styleeditor/test/browser_styleeditor_reload.js b/browser/devtools/styleeditor/test/browser_styleeditor_reload.js new file mode 100644 index 000000000000..267fbcffeb08 --- /dev/null +++ b/browser/devtools/styleeditor/test/browser_styleeditor_reload.js @@ -0,0 +1,99 @@ +/* vim: set ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +const TESTCASE_URI = TEST_BASE_HTTPS + "simple.html"; +const NEW_URI = TEST_BASE_HTTPS + "media.html"; + +const LINE_NO = 5; +const COL_NO = 3; + +let gContentWin; +let gUI; + +function test() +{ + waitForExplicitFinish(); + + addTabAndOpenStyleEditor(function(panel) { + gContentWin = gBrowser.selectedTab.linkedBrowser.contentWindow.wrappedJSObject; + gUI = panel.UI; + + let count = 0; + gUI.on("editor-added", function editorAdded(event, editor) { + if (++count == 2) { + gUI.off("editor-added", editorAdded); + gUI.editors[0].getSourceEditor().then(runTests); + } + }) + }); + + content.location = TESTCASE_URI; +} + +function runTests() +{ + let count = 0; + gUI.once("editor-selected", (event, editor) => { + editor.getSourceEditor().then(() => { + info("selected second editor, about to reload page"); + reloadPage(); + + gUI.on("editor-added", function editorAdded(event, editor) { + if (++count == 2) { + gUI.off("editor-added", editorAdded); + gUI.editors[1].getSourceEditor().then(testRemembered); + } + }) + }); + }); + gUI.selectStyleSheet(gUI.editors[1].styleSheet.href, LINE_NO, COL_NO); +} + +function testRemembered() +{ + is(gUI.selectedEditor, gUI.editors[1], "second editor is selected"); + + let {line, col} = gUI.selectedEditor.sourceEditor.getCaretPosition(); + is(line, LINE_NO, "correct line selected"); + is(col, COL_NO, "correct column selected"); + + testNewPage(); +} + +function testNewPage() +{ + let count = 0; + gUI.on("editor-added", function editorAdded(event, editor) { + info("editor added here") + if (++count == 2) { + gUI.off("editor-added", editorAdded); + gUI.editors[0].getSourceEditor().then(testNotRemembered); + } + }) + + info("navigating to a different page"); + navigatePage(); +} + +function testNotRemembered() +{ + is(gUI.selectedEditor, gUI.editors[0], "first editor is selected"); + + let {line, col} = gUI.selectedEditor.sourceEditor.getCaretPosition(); + is(line, 0, "first line is selected"); + is(col, 0, "first column is selected"); + + gUI = null; + finish(); +} + +function reloadPage() +{ + gContentWin.location.reload(); +} + +function navigatePage() +{ + gContentWin.location = NEW_URI; +} \ No newline at end of file From 0c6e598a67e342ad2bd70095e7543f959f43241d Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Thu, 13 Jun 2013 18:21:06 -0700 Subject: [PATCH 26/84] Bug 882986 - A source map's sourcesContent doesn't work when the original file path is absolute; r=dcamp --- .../server/tests/unit/test_sourcemaps-08.js | 52 ++++++++ .../devtools/server/tests/unit/xpcshell.ini | 1 + toolkit/devtools/sourcemap/SourceMap.jsm | 70 ++++++++-- .../devtools/sourcemap/tests/unit/Utils.jsm | 28 +++- .../tests/unit/test_source_map_consumer.js | 15 +++ .../tests/unit/test_source_map_generator.js | 120 ++++++++++++++++++ 6 files changed, 273 insertions(+), 13 deletions(-) create mode 100644 toolkit/devtools/server/tests/unit/test_sourcemaps-08.js diff --git a/toolkit/devtools/server/tests/unit/test_sourcemaps-08.js b/toolkit/devtools/server/tests/unit/test_sourcemaps-08.js new file mode 100644 index 000000000000..a56a824762cd --- /dev/null +++ b/toolkit/devtools/server/tests/unit/test_sourcemaps-08.js @@ -0,0 +1,52 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Regression test for bug 882986 regarding sourcesContent and absolute source + * URLs. + */ + +var gDebuggee; +var gClient; +var gThreadClient; + +Components.utils.import("resource:///modules/devtools/SourceMap.jsm"); + +function run_test() +{ + initTestDebuggerServer(); + gDebuggee = addTestGlobal("test-source-map"); + gClient = new DebuggerClient(DebuggerServer.connectPipe()); + gClient.connect(function() { + attachTestTabAndResume(gClient, "test-source-map", function(aResponse, aTabClient, aThreadClient) { + gThreadClient = aThreadClient; + test_source_maps(); + }); + }); + do_test_pending(); +} + +function test_source_maps() +{ + gClient.addOneTimeListener("newSource", function (aEvent, aPacket) { + let sourceClient = gThreadClient.source(aPacket.source); + sourceClient.source(function ({error, source}) { + do_check_true(!error, "should be able to grab the source"); + do_check_eq(source, "foo", + "Should load the source from the sourcesContent field"); + finishClient(gClient); + }); + }); + + let code = "'nothing here';\n"; + code += "//# sourceMappingURL=data:text/json," + JSON.stringify({ + version: 3, + file: "foo.js", + sources: ["/a"], + names: [], + mappings: "AACA", + sourcesContent: ["foo"] + }); + Components.utils.evalInSandbox(code, gDebuggee, "1.8", + "http://example.com/foo.js", 1); +} diff --git a/toolkit/devtools/server/tests/unit/xpcshell.ini b/toolkit/devtools/server/tests/unit/xpcshell.ini index da19a6b7c45f..64ff7ab0951c 100644 --- a/toolkit/devtools/server/tests/unit/xpcshell.ini +++ b/toolkit/devtools/server/tests/unit/xpcshell.ini @@ -96,6 +96,7 @@ reason = bug 820380 [test_sourcemaps-07.js] skip-if = toolkit == "gonk" reason = bug 820380 +[test_sourcemaps-08.js] [test_objectgrips-01.js] [test_objectgrips-02.js] [test_objectgrips-03.js] diff --git a/toolkit/devtools/sourcemap/SourceMap.jsm b/toolkit/devtools/sourcemap/SourceMap.jsm index 05139f7969d9..5e965ead98a8 100644 --- a/toolkit/devtools/sourcemap/SourceMap.jsm +++ b/toolkit/devtools/sourcemap/SourceMap.jsm @@ -326,17 +326,21 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'sou } if (this.sourceRoot) { - // Try to remove the sourceRoot - var relativeUrl = util.relative(this.sourceRoot, aSource); - if (this._sources.has(relativeUrl)) { - return this.sourcesContent[this._sources.indexOf(relativeUrl)]; - } + aSource = util.relative(this.sourceRoot, aSource); } if (this._sources.has(aSource)) { return this.sourcesContent[this._sources.indexOf(aSource)]; } + var url; + if (this.sourceRoot + && (url = util.urlParse(this.sourceRoot)) + && (!url.path || url.path == "/") + && this._sources.has("/" + aSource)) { + return this.sourcesContent[this._sources.indexOf("/" + aSource)]; + } + throw new Error('"' + aSource + '" is not in the SourceMap.'); }; @@ -485,6 +489,25 @@ define('source-map/util', ['require', 'exports', 'module' , ], function(require, path: match[7] }; } + exports.urlParse = urlParse; + + function urlGenerate(aParsedUrl) { + var url = aParsedUrl.scheme + "://"; + if (aParsedUrl.auth) { + url += aParsedUrl.auth + "@" + } + if (aParsedUrl.host) { + url += aParsedUrl.host; + } + if (aParsedUrl.port) { + url += ":" + aParsedUrl.port + } + if (aParsedUrl.path) { + url += aParsedUrl.path; + } + return url; + } + exports.urlGenerate = urlGenerate; function join(aRoot, aPath) { var url; @@ -494,7 +517,8 @@ define('source-map/util', ['require', 'exports', 'module' , ], function(require, } if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) { - return aRoot.replace(url.path, '') + aPath; + url.path = aPath; + return urlGenerate(url); } return aRoot.replace(/\/$/, '') + '/' + aPath; @@ -522,6 +546,12 @@ define('source-map/util', ['require', 'exports', 'module' , ], function(require, function relative(aRoot, aPath) { aRoot = aRoot.replace(/\/$/, ''); + + var url = urlParse(aRoot); + if (aPath.charAt(0) == "/" && url && url.path == "/") { + return aPath.slice(1); + } + return aPath.indexOf(aRoot + '/') === 0 ? aPath.substr(aRoot.length + 1) : aPath; @@ -1130,6 +1160,24 @@ define('source-map/source-map-generator', ['require', 'exports', 'module' , 'so } }; + function cmpLocation(loc1, loc2) { + var cmp = (loc1 && loc1.line) - (loc2 && loc2.line); + return cmp ? cmp : (loc1 && loc1.column) - (loc2 && loc2.column); + } + + function strcmp(str1, str2) { + str1 = str1 || ''; + str2 = str2 || ''; + return (str1 > str2) - (str1 < str2); + } + + function cmpMapping(mappingA, mappingB) { + return cmpLocation(mappingA.generated, mappingB.generated) || + cmpLocation(mappingA.original, mappingB.original) || + strcmp(mappingA.source, mappingB.source) || + strcmp(mappingA.name, mappingB.name); + } + /** * Serialize the accumulated mappings in to the stream of base 64 VLQs * specified by the source map format. @@ -1150,12 +1198,7 @@ define('source-map/source-map-generator', ['require', 'exports', 'module' , 'so // via the ';' separators) will be all messed up. Note: it might be more // performant to maintain the sorting as we insert them, rather than as we // serialize them, but the big O is the same either way. - this._mappings.sort(function (mappingA, mappingB) { - var cmp = mappingA.generated.line - mappingB.generated.line; - return cmp === 0 - ? mappingA.generated.column - mappingB.generated.column - : cmp; - }); + this._mappings.sort(cmpMapping); for (var i = 0, len = this._mappings.length; i < len; i++) { mapping = this._mappings[i]; @@ -1169,6 +1212,9 @@ define('source-map/source-map-generator', ['require', 'exports', 'module' , 'so } else { if (i > 0) { + if (!cmpMapping(mapping, this._mappings[i - 1])) { + continue; + } result += ','; } } diff --git a/toolkit/devtools/sourcemap/tests/unit/Utils.jsm b/toolkit/devtools/sourcemap/tests/unit/Utils.jsm index d78371f3757b..706c78f6fe53 100644 --- a/toolkit/devtools/sourcemap/tests/unit/Utils.jsm +++ b/toolkit/devtools/sourcemap/tests/unit/Utils.jsm @@ -265,6 +265,25 @@ define('lib/source-map/util', ['require', 'exports', 'module' , ], function(requ path: match[7] }; } + exports.urlParse = urlParse; + + function urlGenerate(aParsedUrl) { + var url = aParsedUrl.scheme + "://"; + if (aParsedUrl.auth) { + url += aParsedUrl.auth + "@" + } + if (aParsedUrl.host) { + url += aParsedUrl.host; + } + if (aParsedUrl.port) { + url += ":" + aParsedUrl.port + } + if (aParsedUrl.path) { + url += aParsedUrl.path; + } + return url; + } + exports.urlGenerate = urlGenerate; function join(aRoot, aPath) { var url; @@ -274,7 +293,8 @@ define('lib/source-map/util', ['require', 'exports', 'module' , ], function(requ } if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) { - return aRoot.replace(url.path, '') + aPath; + url.path = aPath; + return urlGenerate(url); } return aRoot.replace(/\/$/, '') + '/' + aPath; @@ -302,6 +322,12 @@ define('lib/source-map/util', ['require', 'exports', 'module' , ], function(requ function relative(aRoot, aPath) { aRoot = aRoot.replace(/\/$/, ''); + + var url = urlParse(aRoot); + if (aPath.charAt(0) == "/" && url && url.path == "/") { + return aPath.slice(1); + } + return aPath.indexOf(aRoot + '/') === 0 ? aPath.substr(aRoot.length + 1) : aPath; diff --git a/toolkit/devtools/sourcemap/tests/unit/test_source_map_consumer.js b/toolkit/devtools/sourcemap/tests/unit/test_source_map_consumer.js index 515287004df1..c04cbcb12a58 100644 --- a/toolkit/devtools/sourcemap/tests/unit/test_source_map_consumer.js +++ b/toolkit/devtools/sourcemap/tests/unit/test_source_map_consumer.js @@ -293,6 +293,21 @@ define("test/source-map/test-source-map-consumer", ["require", "exports", "modul 'Source should be relative the host of the source root.'); }; + exports['test github issue #64'] = function (assert, util) { + var map = new SourceMapConsumer({ + "version": 3, + "file": "foo.js", + "sourceRoot": "http://example.com/", + "sources": ["/a"], + "names": [], + "mappings": "AACA", + "sourcesContent": ["foo"] + }); + + assert.equal(map.sourceContentFor("a"), "foo"); + assert.equal(map.sourceContentFor("/a"), "foo"); + }; + }); function run_test() { runSourceMapTests('test/source-map/test-source-map-consumer', do_throw); diff --git a/toolkit/devtools/sourcemap/tests/unit/test_source_map_generator.js b/toolkit/devtools/sourcemap/tests/unit/test_source_map_generator.js index 4811438935dc..39a29e39e50f 100644 --- a/toolkit/devtools/sourcemap/tests/unit/test_source_map_generator.js +++ b/toolkit/devtools/sourcemap/tests/unit/test_source_map_generator.js @@ -273,6 +273,126 @@ define("test/source-map/test-source-map-generator", ["require", "exports", "modu util.assertEqualMaps(assert, actualMap, expectedMap); }; + + exports['test sorting with duplicate generated mappings'] = function (assert, util) { + var map = new SourceMapGenerator({ + file: 'test.js' + }); + map.addMapping({ + generated: { line: 3, column: 0 }, + original: { line: 2, column: 0 }, + source: 'a.js' + }); + map.addMapping({ + generated: { line: 2, column: 0 } + }); + map.addMapping({ + generated: { line: 2, column: 0 } + }); + map.addMapping({ + generated: { line: 1, column: 0 }, + original: { line: 1, column: 0 }, + source: 'a.js' + }); + + util.assertEqualMaps(assert, map.toJSON(), { + version: 3, + file: 'test.js', + sources: ['a.js'], + names: [], + mappings: 'AAAA;A;AACA' + }); + }; + + exports['test ignore duplicate mappings.'] = function (assert, util) { + var init = { file: 'min.js', sourceRoot: '/the/root' }; + var map1, map2; + + // null original source location + var nullMapping1 = { + generated: { line: 1, column: 0 } + }; + var nullMapping2 = { + generated: { line: 2, column: 2 } + }; + + map1 = new SourceMapGenerator(init); + map2 = new SourceMapGenerator(init); + + map1.addMapping(nullMapping1); + map1.addMapping(nullMapping1); + + map2.addMapping(nullMapping1); + + util.assertEqualMaps(assert, map1.toJSON(), map2.toJSON()); + + map1.addMapping(nullMapping2); + map1.addMapping(nullMapping1); + + map2.addMapping(nullMapping2); + + util.assertEqualMaps(assert, map1.toJSON(), map2.toJSON()); + + // original source location + var srcMapping1 = { + generated: { line: 1, column: 0 }, + original: { line: 11, column: 0 }, + source: 'srcMapping1.js' + }; + var srcMapping2 = { + generated: { line: 2, column: 2 }, + original: { line: 11, column: 0 }, + source: 'srcMapping2.js' + }; + + map1 = new SourceMapGenerator(init); + map2 = new SourceMapGenerator(init); + + map1.addMapping(srcMapping1); + map1.addMapping(srcMapping1); + + map2.addMapping(srcMapping1); + + util.assertEqualMaps(assert, map1.toJSON(), map2.toJSON()); + + map1.addMapping(srcMapping2); + map1.addMapping(srcMapping1); + + map2.addMapping(srcMapping2); + + util.assertEqualMaps(assert, map1.toJSON(), map2.toJSON()); + + // full original source and name information + var fullMapping1 = { + generated: { line: 1, column: 0 }, + original: { line: 11, column: 0 }, + source: 'fullMapping1.js', + name: 'fullMapping1' + }; + var fullMapping2 = { + generated: { line: 2, column: 2 }, + original: { line: 11, column: 0 }, + source: 'fullMapping2.js', + name: 'fullMapping2' + }; + + map1 = new SourceMapGenerator(init); + map2 = new SourceMapGenerator(init); + + map1.addMapping(fullMapping1); + map1.addMapping(fullMapping1); + + map2.addMapping(fullMapping1); + + util.assertEqualMaps(assert, map1.toJSON(), map2.toJSON()); + + map1.addMapping(fullMapping2); + map1.addMapping(fullMapping1); + + map2.addMapping(fullMapping2); + + util.assertEqualMaps(assert, map1.toJSON(), map2.toJSON()); + }; }); function run_test() { runSourceMapTests('test/source-map/test-source-map-generator', do_throw); From f7e31f61e32ea715b64ced339eb944a70852715e Mon Sep 17 00:00:00 2001 From: Eitan Isaacson Date: Fri, 14 Jun 2013 09:33:17 -0700 Subject: [PATCH 27/84] Bug 882800 - Use IndieUI inspired scroll requests. r=davidb --- accessible/src/jsat/content-script.js | 36 +++++++++++++-------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/accessible/src/jsat/content-script.js b/accessible/src/jsat/content-script.js index 92c36b40383a..f9eecbe4fc0c 100644 --- a/accessible/src/jsat/content-script.js +++ b/accessible/src/jsat/content-script.js @@ -16,6 +16,8 @@ XPCOMUtils.defineLazyModuleGetter(this, 'Utils', 'resource://gre/modules/accessibility/Utils.jsm'); XPCOMUtils.defineLazyModuleGetter(this, 'EventManager', 'resource://gre/modules/accessibility/EventManager.jsm'); +XPCOMUtils.defineLazyModuleGetter(this, 'ObjectWrapper', + 'resource://gre/modules/ObjectWrapper.jsm'); Logger.debug('content-script.js'); @@ -182,6 +184,21 @@ function scroll(aMessage) { while (acc) { let elem = acc.DOMNode; + // This is inspired by IndieUI events. Once they are + // implemented, it should be easy to transition to them. + // https://dvcs.w3.org/hg/IndieUI/raw-file/tip/src/indie-ui-events.html#scrollrequest + let uiactions = elem.getAttribute ? elem.getAttribute('uiactions') : ''; + if (uiactions && uiactions.split(' ').indexOf('scroll') >= 0) { + let evt = elem.ownerDocument.createEvent('CustomEvent'); + let details = horiz ? { deltaX: page * elem.clientWidth } : + { deltaY: page * elem.clientHeight }; + evt.initCustomEvent( + 'scrollrequest', true, true, + ObjectWrapper.wrap(details, elem.ownerDocument.defaultView)); + if (!elem.dispatchEvent(evt)) + return; + } + // We will do window scrolling next. if (elem == content.document) break; @@ -202,25 +219,6 @@ function scroll(aMessage) { return true; } } - - let controllers = acc. - getRelationByType( - Ci.nsIAccessibleRelation.RELATION_CONTROLLED_BY); - for (let i = 0; controllers.targetsCount > i; i++) { - let controller = controllers.getTarget(i); - // If the section has a controlling slider, it should be considered - // the page-turner. - if (controller.role == Ci.nsIAccessibleRole.ROLE_SLIDER) { - // Sliders are controlled with ctrl+right/left. I just decided :) - let evt = content.document.createEvent('KeyboardEvent'); - evt.initKeyEvent( - 'keypress', true, true, null, - true, false, false, false, - (page > 0) ? evt.DOM_VK_RIGHT : evt.DOM_VK_LEFT, 0); - controller.DOMNode.dispatchEvent(evt); - return true; - } - } } acc = acc.parent; } From cece851ab2e145ce905677ab04b5af30dbc42298 Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Fri, 14 Jun 2013 12:42:10 -0400 Subject: [PATCH 28/84] Bug 863777 - Add types to jni-generator.py; r=kats --- mobile/android/base/jni-generator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/android/base/jni-generator.py b/mobile/android/base/jni-generator.py index 577cea059b3d..ddcbb9e1d1bb 100644 --- a/mobile/android/base/jni-generator.py +++ b/mobile/android/base/jni-generator.py @@ -67,7 +67,7 @@ class Generator: paramNames = ['arg%d' % i for i in range(0, len(paramTypes))] if returnType == 'void': returnValue = '' - elif returnType == 'jobject': + elif returnType in ('jobject', 'jstring'): returnValue = 'NULL' elif returnType in ('jint', 'jfloat', 'jdouble', 'jlong'): returnValue = '0' From 3f9f3d0dd59c402d4c94ec9b142f6de5f5ea2012 Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Fri, 14 Jun 2013 12:42:10 -0400 Subject: [PATCH 29/84] Bug 863777 - Add native stack JNI method definitions; r=kats --- mobile/android/base/ANRReporter.java | 4 ++ mobile/android/base/Makefile.in | 1 + mozglue/android/jni-stubs.inc | 57 ++++++++++++++++++++++++++++ widget/android/AndroidJNI.cpp | 18 +++++++++ 4 files changed, 80 insertions(+) diff --git a/mobile/android/base/ANRReporter.java b/mobile/android/base/ANRReporter.java index 213f1fecddd3..8ef79dd5ffd3 100644 --- a/mobile/android/base/ANRReporter.java +++ b/mobile/android/base/ANRReporter.java @@ -62,6 +62,10 @@ public final class ANRReporter extends BroadcastReceiver private Handler mHandler; private volatile boolean mPendingANR; + private static native boolean requestNativeStack(); + private static native String getNativeStack(); + private static native void releaseNativeStack(); + public static void register(Context context) { if (sRegisteredCount++ != 0) { // Already registered diff --git a/mobile/android/base/Makefile.in b/mobile/android/base/Makefile.in index 70816d829ec1..896b62463ece 100644 --- a/mobile/android/base/Makefile.in +++ b/mobile/android/base/Makefile.in @@ -1218,6 +1218,7 @@ CLASSES_WITH_JNI= \ org.mozilla.gecko.GeckoAppShell \ org.mozilla.gecko.GeckoJavaSampler \ org.mozilla.gecko.gfx.NativePanZoomController \ + org.mozilla.gecko.ANRReporter \ $(NULL) ifdef MOZ_WEBSMS_BACKEND diff --git a/mozglue/android/jni-stubs.inc b/mozglue/android/jni-stubs.inc index db32290ed9e4..2fb938265258 100644 --- a/mozglue/android/jni-stubs.inc +++ b/mozglue/android/jni-stubs.inc @@ -569,3 +569,60 @@ Java_org_mozilla_gecko_gfx_NativePanZoomController_getOverScrollMode(JNIEnv * ar xul_dlsym("Java_org_mozilla_gecko_gfx_NativePanZoomController_getOverScrollMode", &f_Java_org_mozilla_gecko_gfx_NativePanZoomController_getOverScrollMode); #endif +#ifdef JNI_STUBS + +typedef jboolean (*Java_org_mozilla_gecko_ANRReporter_requestNativeStack_t)(JNIEnv *, jclass); +static Java_org_mozilla_gecko_ANRReporter_requestNativeStack_t f_Java_org_mozilla_gecko_ANRReporter_requestNativeStack; +extern "C" NS_EXPORT jboolean JNICALL +Java_org_mozilla_gecko_ANRReporter_requestNativeStack(JNIEnv * arg0, jclass arg1) { + if (!f_Java_org_mozilla_gecko_ANRReporter_requestNativeStack) { + arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"), + "JNI Function called before it was loaded"); + return false; + } + return f_Java_org_mozilla_gecko_ANRReporter_requestNativeStack(arg0, arg1); +} +#endif + +#ifdef JNI_BINDINGS + xul_dlsym("Java_org_mozilla_gecko_ANRReporter_requestNativeStack", &f_Java_org_mozilla_gecko_ANRReporter_requestNativeStack); +#endif + +#ifdef JNI_STUBS + +typedef jstring (*Java_org_mozilla_gecko_ANRReporter_getNativeStack_t)(JNIEnv *, jclass); +static Java_org_mozilla_gecko_ANRReporter_getNativeStack_t f_Java_org_mozilla_gecko_ANRReporter_getNativeStack; +extern "C" NS_EXPORT jstring JNICALL +Java_org_mozilla_gecko_ANRReporter_getNativeStack(JNIEnv * arg0, jclass arg1) { + if (!f_Java_org_mozilla_gecko_ANRReporter_getNativeStack) { + arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"), + "JNI Function called before it was loaded"); + return NULL; + } + return f_Java_org_mozilla_gecko_ANRReporter_getNativeStack(arg0, arg1); +} +#endif + +#ifdef JNI_BINDINGS + xul_dlsym("Java_org_mozilla_gecko_ANRReporter_getNativeStack", &f_Java_org_mozilla_gecko_ANRReporter_getNativeStack); +#endif + +#ifdef JNI_STUBS + +typedef void (*Java_org_mozilla_gecko_ANRReporter_releaseNativeStack_t)(JNIEnv *, jclass); +static Java_org_mozilla_gecko_ANRReporter_releaseNativeStack_t f_Java_org_mozilla_gecko_ANRReporter_releaseNativeStack; +extern "C" NS_EXPORT void JNICALL +Java_org_mozilla_gecko_ANRReporter_releaseNativeStack(JNIEnv * arg0, jclass arg1) { + if (!f_Java_org_mozilla_gecko_ANRReporter_releaseNativeStack) { + arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"), + "JNI Function called before it was loaded"); + return ; + } + f_Java_org_mozilla_gecko_ANRReporter_releaseNativeStack(arg0, arg1); +} +#endif + +#ifdef JNI_BINDINGS + xul_dlsym("Java_org_mozilla_gecko_ANRReporter_releaseNativeStack", &f_Java_org_mozilla_gecko_ANRReporter_releaseNativeStack); +#endif + diff --git a/widget/android/AndroidJNI.cpp b/widget/android/AndroidJNI.cpp index 30869cfd8cdb..7e4ce136c0e8 100644 --- a/widget/android/AndroidJNI.cpp +++ b/widget/android/AndroidJNI.cpp @@ -976,4 +976,22 @@ Java_org_mozilla_gecko_gfx_NativePanZoomController_getOverScrollMode(JNIEnv* env return 0; } +NS_EXPORT jboolean JNICALL +Java_org_mozilla_gecko_ANRReporter_requestNativeStack(JNIEnv*, jclass) +{ + return JNI_FALSE; +} + +NS_EXPORT jstring JNICALL +Java_org_mozilla_gecko_ANRReporter_getNativeStack(JNIEnv* jenv, jclass) +{ + return NULL; +} + +NS_EXPORT void JNICALL +Java_org_mozilla_gecko_ANRReporter_releaseNativeStack(JNIEnv* jenv, jclass) +{ + return; +} + } From d1065596123ec7885ad8392be79252bf306f8a3f Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Fri, 14 Jun 2013 12:42:10 -0400 Subject: [PATCH 30/84] Bug 863777 - Implement native stack JNI calls using the profiler API; r=BenWa --- widget/android/AndroidJNI.cpp | 40 ++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/widget/android/AndroidJNI.cpp b/widget/android/AndroidJNI.cpp index 7e4ce136c0e8..609878dd829f 100644 --- a/widget/android/AndroidJNI.cpp +++ b/widget/android/AndroidJNI.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include "nsAppShell.h" #include "nsWindow.h" @@ -41,6 +42,8 @@ #include "nsSurfaceTexture.h" #include "GeckoProfiler.h" +#include "GeckoProfiler.h" + using namespace mozilla; using namespace mozilla::dom; using namespace mozilla::dom::mobilemessage; @@ -979,19 +982,50 @@ Java_org_mozilla_gecko_gfx_NativePanZoomController_getOverScrollMode(JNIEnv* env NS_EXPORT jboolean JNICALL Java_org_mozilla_gecko_ANRReporter_requestNativeStack(JNIEnv*, jclass) { - return JNI_FALSE; + if (profiler_is_active()) { + // Don't proceed if profiler is already running + return JNI_FALSE; + } + // WARNING: we are on the ANR reporter thread at this point and it is + // generally unsafe to use the profiler from off the main thread. However, + // the risk here is limited because for most users, the profiler is not run + // elsewhere. See the discussion in Bug 863777, comment 13 + const char *NATIVE_STACK_FEATURES[] = {"leaf", "threads"}; + // Buffer one sample and let the profiler wait a long time + profiler_start(100, 10000, NATIVE_STACK_FEATURES, + sizeof(NATIVE_STACK_FEATURES) / sizeof(char*)); + return JNI_TRUE; } NS_EXPORT jstring JNICALL Java_org_mozilla_gecko_ANRReporter_getNativeStack(JNIEnv* jenv, jclass) { - return NULL; + if (!profiler_is_active()) { + // Maybe profiler support is disabled? + return NULL; + } + char *profile = profiler_get_profile(); + while (profile && !strlen(profile)) { + // no sample yet? + sched_yield(); + profile = profiler_get_profile(); + } + jstring result = NULL; + if (profile) { + result = jenv->NewStringUTF(profile); + free(profile); + } + return result; } NS_EXPORT void JNICALL Java_org_mozilla_gecko_ANRReporter_releaseNativeStack(JNIEnv* jenv, jclass) { - return; + if (!profiler_is_active()) { + // Maybe profiler support is disabled? + return; + } + mozilla_sampler_stop(); } } From 43b7d547995455b39b87983d97a25301dfa8e0e5 Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Fri, 14 Jun 2013 12:42:10 -0400 Subject: [PATCH 31/84] Bug 863777 - Get native stack in ANR report; r=blassey --- mobile/android/base/ANRReporter.java | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/mobile/android/base/ANRReporter.java b/mobile/android/base/ANRReporter.java index 8ef79dd5ffd3..39567d8d139b 100644 --- a/mobile/android/base/ANRReporter.java +++ b/mobile/android/base/ANRReporter.java @@ -30,6 +30,7 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.Reader; +import java.io.StringReader; import java.security.GeneralSecurityException; import java.security.MessageDigest; import java.util.UUID; @@ -445,7 +446,8 @@ public final class ANRReporter extends BroadcastReceiver return total; } - private static void fillPingFooter(OutputStream ping, MessageDigest checksum) + private static void fillPingFooter(OutputStream ping, MessageDigest checksum, + boolean haveNativeStack) throws IOException { // We are at the end of ANR data @@ -473,6 +475,17 @@ public final class ANRReporter extends BroadcastReceiver Log.w(LOGTAG, e); } + if (haveNativeStack) { + total += writePingPayload(ping, checksum, ("\"," + + "\"androidNativeStack\":\"")); + + String nativeStack = String.valueOf(getNativeStack()); + int size = fillPingBlock(ping, checksum, new StringReader(nativeStack), null); + if (DEBUG) { + Log.d(LOGTAG, "wrote native stack, size = " + String.valueOf(size)); + } + } + total += writePingPayload(ping, checksum, "\"}"); String base64Checksum = Base64.encodeToString(checksum.digest(), Base64.NO_WRAP); @@ -490,6 +503,8 @@ public final class ANRReporter extends BroadcastReceiver } private static void processTraces(Reader traces, File pingFile) { + + boolean haveNativeStack = requestNativeStack(); try { OutputStream ping = new BufferedOutputStream( new FileOutputStream(pingFile), TRACES_BLOCK_SIZE); @@ -511,13 +526,16 @@ public final class ANRReporter extends BroadcastReceiver if (DEBUG) { Log.d(LOGTAG, "wrote traces, size = " + String.valueOf(size)); } - fillPingFooter(ping, checksum); + fillPingFooter(ping, checksum, haveNativeStack); if (DEBUG) { Log.d(LOGTAG, "finished creating ping file"); } return; } finally { ping.close(); + if (haveNativeStack) { + releaseNativeStack(); + } } } catch (GeneralSecurityException e) { Log.w(LOGTAG, e); From 379f413a132b60c63445f16e8ae10433dd39d372 Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Fri, 14 Jun 2013 12:42:10 -0400 Subject: [PATCH 32/84] Bug 863777 - Letting profiler start/stop from a non-registered thread; r=BenWa --- tools/profiler/platform.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/tools/profiler/platform.cpp b/tools/profiler/platform.cpp index 9020abf90c35..193509e8c433 100644 --- a/tools/profiler/platform.cpp +++ b/tools/profiler/platform.cpp @@ -409,12 +409,6 @@ void mozilla_sampler_start(int aProfileEntries, int aInterval, if (sUnwindInterval > 0) aInterval = sUnwindInterval; - PseudoStack *stack = tlsPseudoStack.get(); - if (!stack) { - ASSERT(false); - return; - } - // Reset the current state if the profiler is running profiler_stop(); @@ -485,11 +479,12 @@ void mozilla_sampler_stop() t->Stop(); delete t; tlsTicker.set(NULL); - PseudoStack *stack = tlsPseudoStack.get(); - ASSERT(stack != NULL); - if (disableJS) + if (disableJS) { + PseudoStack *stack = tlsPseudoStack.get(); + ASSERT(stack != NULL); stack->disableJSSampling(); + } if (unwinderThreader) { uwt__deinit(); From c98b67af472a9ba4f41e80932ffa98a580486b92 Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Fri, 14 Jun 2013 12:42:10 -0400 Subject: [PATCH 33/84] Bug 863777 - Add and turn on privacy mode in profiler for ANR reports; r=BenWa --- tools/profiler/GeckoProfiler.h | 2 ++ tools/profiler/GeckoProfilerImpl.h | 17 ++++++++++++++++- tools/profiler/PseudoStack.h | 2 ++ tools/profiler/TableTicker.h | 3 +++ tools/profiler/platform.cpp | 11 +++++++++-- widget/android/AndroidJNI.cpp | 2 +- 6 files changed, 33 insertions(+), 4 deletions(-) diff --git a/tools/profiler/GeckoProfiler.h b/tools/profiler/GeckoProfiler.h index a77cc1d3dfd6..e18e81e71288 100644 --- a/tools/profiler/GeckoProfiler.h +++ b/tools/profiler/GeckoProfiler.h @@ -144,6 +144,8 @@ static inline void profiler_js_operation_callback() {} static inline double profiler_time() { return 0; } +static inline bool profiler_in_privacy_mode() { return false; } + #else #include "GeckoProfilerImpl.h" diff --git a/tools/profiler/GeckoProfilerImpl.h b/tools/profiler/GeckoProfilerImpl.h index 89779a209384..484f4a8b55ff 100644 --- a/tools/profiler/GeckoProfilerImpl.h +++ b/tools/profiler/GeckoProfilerImpl.h @@ -169,6 +169,16 @@ double profiler_time() return mozilla_sampler_time(); } +static inline +bool profiler_in_privacy_mode() +{ + PseudoStack *stack = tlsPseudoStack.get(); + if (!stack) { + return false; + } + return stack->mPrivacyMode; +} + // we want the class and function name but can't easily get that using preprocessor macros // __func__ doesn't have the class name and __PRETTY_FUNCTION__ has the parameters @@ -241,7 +251,7 @@ class MOZ_STACK_CLASS SamplerStackFramePrintfRAII { public: // we only copy the strings at save time, so to take multiple parameters we'd need to copy them then. SamplerStackFramePrintfRAII(const char *aDefault, uint32_t line, const char *aFormat, ...) { - if (profiler_is_active()) { + if (profiler_is_active() && !profiler_in_privacy_mode()) { va_list args; va_start(args, aFormat); char buff[SAMPLER_MAX_STRING]; @@ -324,6 +334,11 @@ inline void mozilla_sampler_add_marker(const char *aMarker) return; } + // Don't add a marker if we don't want to include personal information + if (profiler_in_privacy_mode()) { + return; + } + PseudoStack *stack = tlsPseudoStack.get(); if (!stack) { return; diff --git a/tools/profiler/PseudoStack.h b/tools/profiler/PseudoStack.h index b12bb226dae5..feae948a2b18 100644 --- a/tools/profiler/PseudoStack.h +++ b/tools/profiler/PseudoStack.h @@ -111,6 +111,7 @@ public: , mQueueClearMarker(false) , mRuntime(nullptr) , mStartJSSampling(false) + , mPrivacyMode(false) { } void addMarker(const char *aMarker) @@ -249,6 +250,7 @@ public: JSRuntime *mRuntime; // Start JS Profiling when possible bool mStartJSSampling; + bool mPrivacyMode; }; #endif diff --git a/tools/profiler/TableTicker.h b/tools/profiler/TableTicker.h index b0baef983773..2b49dda5e38a 100644 --- a/tools/profiler/TableTicker.h +++ b/tools/profiler/TableTicker.h @@ -42,6 +42,7 @@ class TableTicker: public Sampler { mProfileThreads = hasFeature(aFeatures, aFeatureCount, "threads"); mUnwinderThread = hasFeature(aFeatures, aFeatureCount, "unwinder") || sps_version2(); mAddLeafAddresses = hasFeature(aFeatures, aFeatureCount, "leaf"); + mPrivacyMode = hasFeature(aFeatures, aFeatureCount, "privacy"); sStartTime = TimeStamp::Now(); @@ -127,6 +128,7 @@ class TableTicker: public Sampler { bool ProfileJS() const { return mProfileJS; } bool ProfileJava() const { return mProfileJava; } bool ProfileThreads() const { return mProfileThreads; } + bool InPrivacyMode() const { return mPrivacyMode; } protected: // Called within a signal. This function must be reentrant @@ -150,5 +152,6 @@ protected: bool mProfileThreads; bool mUnwinderThread; bool mProfileJava; + bool mPrivacyMode; }; diff --git a/tools/profiler/platform.cpp b/tools/profiler/platform.cpp index 193509e8c433..fe01ffed03d6 100644 --- a/tools/profiler/platform.cpp +++ b/tools/profiler/platform.cpp @@ -391,6 +391,8 @@ const char** mozilla_sampler_get_features() "js", // Profile the registered secondary threads. "threads", + // Do not include user-identifiable information + "privacy", NULL }; @@ -423,7 +425,7 @@ void mozilla_sampler_start(int aProfileEntries, int aInterval, tlsTicker.set(t); t->Start(); - if (t->ProfileJS()) { + if (t->ProfileJS() || t->InPrivacyMode()) { mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex); std::vector threads = t->GetRegisteredThreads(); @@ -433,7 +435,12 @@ void mozilla_sampler_start(int aProfileEntries, int aInterval, if (!thread_profile) { continue; } - thread_profile->GetPseudoStack()->enableJSSampling(); + if (t->ProfileJS()) { + thread_profile->GetPseudoStack()->enableJSSampling(); + } + if (t->InPrivacyMode()) { + thread_profile->GetPseudoStack()->mPrivacyMode = true; + } } } diff --git a/widget/android/AndroidJNI.cpp b/widget/android/AndroidJNI.cpp index 609878dd829f..2ff9061db5c8 100644 --- a/widget/android/AndroidJNI.cpp +++ b/widget/android/AndroidJNI.cpp @@ -990,7 +990,7 @@ Java_org_mozilla_gecko_ANRReporter_requestNativeStack(JNIEnv*, jclass) // generally unsafe to use the profiler from off the main thread. However, // the risk here is limited because for most users, the profiler is not run // elsewhere. See the discussion in Bug 863777, comment 13 - const char *NATIVE_STACK_FEATURES[] = {"leaf", "threads"}; + const char *NATIVE_STACK_FEATURES[] = {"leaf", "threads", "privacy"}; // Buffer one sample and let the profiler wait a long time profiler_start(100, 10000, NATIVE_STACK_FEATURES, sizeof(NATIVE_STACK_FEATURES) / sizeof(char*)); From 9b2727babae61f6dabd27a1dad2918d06913b93b Mon Sep 17 00:00:00 2001 From: Gregory Szorc Date: Fri, 14 Jun 2013 09:44:33 -0700 Subject: [PATCH 34/84] Bug 879406 - Unbust |mach help| when arguments are not prefixed with '-'; r=ted DONTBUILD (NPOTB) --- python/mach/mach/dispatcher.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/python/mach/mach/dispatcher.py b/python/mach/mach/dispatcher.py index f663912d7ce1..1eaceb91e658 100644 --- a/python/mach/mach/dispatcher.py +++ b/python/mach/mach/dispatcher.py @@ -177,8 +177,15 @@ class CommandAction(argparse.Action): # just the command data then supplement the main help's output with # this 2nd parser's. We use a custom formatter class to ignore some of # the help output. - c_parser = argparse.ArgumentParser(formatter_class=CommandFormatter, - add_help=False) + parser_args = { + 'formatter_class': CommandFormatter, + 'add_help': False, + } + + if handler.allow_all_arguments: + parser_args['prefix_chars'] = '+' + + c_parser = argparse.ArgumentParser(**parser_args) group = c_parser.add_argument_group('Command Arguments') From 2925313d8d31d4adeb7657b24cc3255e4209dab7 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Fri, 14 Jun 2013 19:10:12 +0200 Subject: [PATCH 35/84] Bug 877277 - Followup: use the right macro to declare nsISupports; r=smaug over IRC --- content/html/document/src/nsHTMLDocument.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/html/document/src/nsHTMLDocument.h b/content/html/document/src/nsHTMLDocument.h index 364e4173db43..f88b6a5e8e49 100644 --- a/content/html/document/src/nsHTMLDocument.h +++ b/content/html/document/src/nsHTMLDocument.h @@ -44,7 +44,7 @@ public: ~nsHTMLDocument(); virtual nsresult Init() MOZ_OVERRIDE; - NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(nsHTMLDocument, nsDocument) From ade3ed8e0df0c5e9223fa69caaa7e8fe1bdb0825 Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Fri, 14 Jun 2013 20:10:22 +0300 Subject: [PATCH 36/84] Bug 883096 - Crash at nsEventListenerManager::GetListenerInfo, r=jst --HG-- extra : rebase_source : 2073283f4b23586fac0a3ae4243a50b745912a20 --- content/events/public/nsIEventListenerService.idl | 1 + content/events/src/nsEventListenerManager.cpp | 8 ++++++-- content/events/test/test_bug448602.html | 9 +++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/content/events/public/nsIEventListenerService.idl b/content/events/public/nsIEventListenerService.idl index 744f509040c8..f9277b030aa6 100644 --- a/content/events/public/nsIEventListenerService.idl +++ b/content/events/public/nsIEventListenerService.idl @@ -16,6 +16,7 @@ interface nsIEventListenerInfo : nsISupports { /** * The type of the event for which the listener was added. + * Null if the listener is for all the events. */ readonly attribute AString type; readonly attribute boolean capturing; diff --git a/content/events/src/nsEventListenerManager.cpp b/content/events/src/nsEventListenerManager.cpp index 06b7febebd92..b0dbfa13ec60 100644 --- a/content/events/src/nsEventListenerManager.cpp +++ b/content/events/src/nsEventListenerManager.cpp @@ -1167,8 +1167,12 @@ nsEventListenerManager::GetListenerInfo(nsCOMArray* aList) CompileEventHandlerInternal(const_cast(&ls), true, nullptr); } - const nsDependentSubstring& eventType = - Substring(nsDependentAtomString(ls.mTypeAtom), 2); + nsAutoString eventType; + if (ls.mAllEvents) { + eventType.SetIsVoid(true); + } else { + eventType.Assign(Substring(nsDependentAtomString(ls.mTypeAtom), 2)); + } // EventListenerInfo is defined in XPCOM, so we have to go ahead // and convert to an XPCOM callback here... nsRefPtr info = diff --git a/content/events/test/test_bug448602.html b/content/events/test/test_bug448602.html index 2878a92a8c88..9b4e2560782c 100644 --- a/content/events/test/test_bug448602.html +++ b/content/events/test/test_bug448602.html @@ -184,6 +184,15 @@ function testAllListener() { } els.addListenerForAllEvents(root, allListener, false, true); + var infos = els.getListenerInfoFor(root); + var nullTypes = 0; + for (var i = 0; i < infos.length; ++i) { + if (infos[i].type == null) { + ++nullTypes; + } + } + is(nullTypes, 1, "Should have one all-event-listener!"); + els.addListenerForAllEvents(root, allListener, false, true, true); els.addListenerForAllEvents(root, allListenerTrustedOnly, false, false, true); l3.dispatchEvent(new Event("testevent", { bubbles: true })); From 41fa141751665b2de851d9033d93eb33fea8040f Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Fri, 14 Jun 2013 10:09:18 -0700 Subject: [PATCH 37/84] Bug 881882 - OdinMonkey: take the percentage back out (it's wrong and misleading with parallel compilation) (r=me) --HG-- extra : rebase_source : 1bec8d8901fbaeb7929b1ca390cfeeae39ef1b0a --- js/src/ion/AsmJS.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/js/src/ion/AsmJS.cpp b/js/src/ion/AsmJS.cpp index 1686ac240c3c..076a851fe1bd 100644 --- a/js/src/ion/AsmJS.cpp +++ b/js/src/ion/AsmJS.cpp @@ -1501,9 +1501,8 @@ class MOZ_STACK_CLASS ModuleCompiler JSAutoByteString name; if (!js_AtomToPrintableString(cx_, func.name, &name)) return; - slowFuns.reset(JS_smprintf("%s%s:%u:%u (%ums, %g%%)%s", slowFuns.get(), + slowFuns.reset(JS_smprintf("%s%s:%u:%u (%ums)%s", slowFuns.get(), name.ptr(), func.line, func.column, func.ms, - double(func.ms)/double(msTotal), i+1 < slowFunctions_.length() ? ", " : "")); if (!slowFuns) return; From 49fb5d684fa6072c47ec8149d5c3eb060b597e42 Mon Sep 17 00:00:00 2001 From: Dave Hunt Date: Fri, 14 Jun 2013 13:21:29 -0400 Subject: [PATCH 38/84] Bug 879683 - Allow MarionetteTestResult and MarionetteTextTestRunner to be subclassed. r=jgriffin --- testing/marionette/client/marionette/__init__.py | 2 ++ testing/marionette/client/marionette/runtests.py | 9 ++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/testing/marionette/client/marionette/__init__.py b/testing/marionette/client/marionette/__init__.py index e78bd0c53801..e86e22de5968 100644 --- a/testing/marionette/client/marionette/__init__.py +++ b/testing/marionette/client/marionette/__init__.py @@ -6,5 +6,7 @@ from gestures import * from marionette import Marionette, HTMLElement, Actions, MultiActions from marionette_test import MarionetteTestCase, CommonTestCase from emulator import Emulator +from runtests import MarionetteTestResult from runtests import MarionetteTestRunner from runtests import MarionetteTestOptions +from runtests import MarionetteTextTestRunner diff --git a/testing/marionette/client/marionette/runtests.py b/testing/marionette/client/marionette/runtests.py index d9b3d197b683..b0415d161811 100644 --- a/testing/marionette/client/marionette/runtests.py +++ b/testing/marionette/client/marionette/runtests.py @@ -71,7 +71,8 @@ class MarionetteTestResult(unittest._TextTestResult): self.stream.writeln('END LOG:') def printErrorList(self, flavour, errors): - for test, err in errors: + for error in errors: + test, err = error[:2] self.stream.writeln(self.separator1) self.stream.writeln("%s: %s" % (flavour, self.getDescription(test))) self.stream.writeln(self.separator2) @@ -169,6 +170,8 @@ class MarionetteTextTestRunner(unittest.TextTestRunner): class MarionetteTestRunner(object): + textrunnerclass = MarionetteTextTestRunner + def __init__(self, address=None, emulator=None, emulatorBinary=None, emulatorImg=None, emulator_res='480x800', homedir=None, app=None, bin=None, profile=None, autolog=False, revision=None, @@ -440,8 +443,8 @@ class MarionetteTestRunner(object): break if suite.countTestCases(): - runner = MarionetteTextTestRunner(verbosity=3, - marionette=self.marionette) + runner = self.textrunnerclass(verbosity=3, + marionette=self.marionette) results = runner.run(suite) self.results.append(results) From f31d4e7e40e75abec6907dbbe9ea54829b5ce9d2 Mon Sep 17 00:00:00 2001 From: Trevor Saunders Date: Fri, 7 Jun 2013 15:49:03 -0400 Subject: [PATCH 39/84] bug 809306 - fix a bunch of static initializers caused by ion monkey's assembler headers r=dvander --- js/src/ion/RangeAnalysis.cpp | 5 - js/src/ion/RangeAnalysis.h | 3 +- js/src/ion/RegisterAllocator.h | 6 +- js/src/ion/RegisterSets.h | 16 ++-- js/src/ion/arm/Assembler-arm.h | 125 +++++++++++++------------ js/src/ion/x64/Assembler-x64.h | 166 ++++++++++++++++----------------- js/src/ion/x86/Assembler-x86.h | 72 +++++++------- 7 files changed, 196 insertions(+), 197 deletions(-) diff --git a/js/src/ion/RangeAnalysis.cpp b/js/src/ion/RangeAnalysis.cpp index fb7db64a222a..33f850eec58e 100644 --- a/js/src/ion/RangeAnalysis.cpp +++ b/js/src/ion/RangeAnalysis.cpp @@ -85,11 +85,6 @@ using mozilla::IsNegative; // after range analysis is performed. The remaining compiler phases do not ever // encounter beta nodes. -RangeAnalysis::RangeAnalysis(MIRGraph &graph) - : graph_(graph) -{ -} - static bool IsDominatedUse(MBasicBlock *block, MUse *use) { diff --git a/js/src/ion/RangeAnalysis.h b/js/src/ion/RangeAnalysis.h index 93e0206ec079..0dc1206eb8ce 100644 --- a/js/src/ion/RangeAnalysis.h +++ b/js/src/ion/RangeAnalysis.h @@ -78,7 +78,8 @@ class RangeAnalysis MIRGraph &graph_; public: - RangeAnalysis(MIRGraph &graph); + MOZ_CONSTEXPR RangeAnalysis(MIRGraph &graph) : + graph_(graph) {} bool addBetaNobes(); bool analyze(); bool removeBetaNobes(); diff --git a/js/src/ion/RegisterAllocator.h b/js/src/ion/RegisterAllocator.h index fe76b3504ee9..751479175827 100644 --- a/js/src/ion/RegisterAllocator.h +++ b/js/src/ion/RegisterAllocator.h @@ -7,6 +7,8 @@ #ifndef js_ion_registerallocator_h__ #define js_ion_registerallocator_h__ +#include "mozilla/Attributes.h" + #include "Ion.h" #include "MIR.h" #include "MIRGraph.h" @@ -140,7 +142,7 @@ struct AllocationIntegrityState class CodePosition { private: - CodePosition(const uint32_t &bits) + MOZ_CONSTEXPR CodePosition(const uint32_t &bits) : bits_(bits) { } @@ -159,7 +161,7 @@ class CodePosition OUTPUT }; - CodePosition() : bits_(0) + MOZ_CONSTEXPR CodePosition() : bits_(0) { } CodePosition(uint32_t instruction, SubPosition where) { diff --git a/js/src/ion/RegisterSets.h b/js/src/ion/RegisterSets.h index dc15038b2c86..9bcf0823e4bd 100644 --- a/js/src/ion/RegisterSets.h +++ b/js/src/ion/RegisterSets.h @@ -92,7 +92,7 @@ class ValueOperand Register payload_; public: - ValueOperand(Register type, Register payload) + MOZ_CONSTEXPR ValueOperand(Register type, Register payload) : type_(type), payload_(payload) { } @@ -117,7 +117,7 @@ class ValueOperand Register value_; public: - explicit ValueOperand(Register value) + explicit MOZ_CONSTEXPR ValueOperand(Register value) : value_(value) { } @@ -297,13 +297,13 @@ class TypedRegisterSet uint32_t bits_; public: - explicit TypedRegisterSet(uint32_t bits) + explicit MOZ_CONSTEXPR TypedRegisterSet(uint32_t bits) : bits_(bits) { } - TypedRegisterSet() : bits_(0) + MOZ_CONSTEXPR TypedRegisterSet() : bits_(0) { } - TypedRegisterSet(const TypedRegisterSet &set) : bits_(set.bits_) + MOZ_CONSTEXPR TypedRegisterSet(const TypedRegisterSet &set) : bits_(set.bits_) { } static inline TypedRegisterSet All() { @@ -471,7 +471,7 @@ class RegisterSet { public: RegisterSet() { } - RegisterSet(const GeneralRegisterSet &gpr, const FloatRegisterSet &fpu) + MOZ_CONSTEXPR RegisterSet(const GeneralRegisterSet &gpr, const FloatRegisterSet &fpu) : gpr_(gpr), fpu_(fpu) { } @@ -579,10 +579,10 @@ class RegisterSet { gpr_.clear(); fpu_.clear(); } - GeneralRegisterSet gprs() const { + MOZ_CONSTEXPR GeneralRegisterSet gprs() const { return gpr_; } - FloatRegisterSet fpus() const { + MOZ_CONSTEXPR FloatRegisterSet fpus() const { return fpu_; } bool operator ==(const RegisterSet &other) const { diff --git a/js/src/ion/arm/Assembler-arm.h b/js/src/ion/arm/Assembler-arm.h index 68acd6338f16..3d7971db23bd 100644 --- a/js/src/ion/arm/Assembler-arm.h +++ b/js/src/ion/arm/Assembler-arm.h @@ -7,6 +7,7 @@ #ifndef jsion_cpu_arm_assembler_h__ #define jsion_cpu_arm_assembler_h__ +#include "mozilla/Attributes.h" #include "mozilla/MathAlgorithms.h" #include "mozilla/Util.h" @@ -26,44 +27,44 @@ namespace ion { // clearer than bl r14). HOWEVER, this register can // easily be a gpr when it is not busy holding the return // address. -static const Register r0 = { Registers::r0 }; -static const Register r1 = { Registers::r1 }; -static const Register r2 = { Registers::r2 }; -static const Register r3 = { Registers::r3 }; -static const Register r4 = { Registers::r4 }; -static const Register r5 = { Registers::r5 }; -static const Register r6 = { Registers::r6 }; -static const Register r7 = { Registers::r7 }; -static const Register r8 = { Registers::r8 }; -static const Register r9 = { Registers::r9 }; -static const Register r10 = { Registers::r10 }; -static const Register r11 = { Registers::r11 }; -static const Register r12 = { Registers::ip }; -static const Register ip = { Registers::ip }; -static const Register sp = { Registers::sp }; -static const Register r14 = { Registers::lr }; -static const Register lr = { Registers::lr }; -static const Register pc = { Registers::pc }; +static const MOZ_CONSTEXPR Register r0 = { Registers::r0 }; +static const MOZ_CONSTEXPR Register r1 = { Registers::r1 }; +static const MOZ_CONSTEXPR Register r2 = { Registers::r2 }; +static const MOZ_CONSTEXPR Register r3 = { Registers::r3 }; +static const MOZ_CONSTEXPR Register r4 = { Registers::r4 }; +static const MOZ_CONSTEXPR Register r5 = { Registers::r5 }; +static const MOZ_CONSTEXPR Register r6 = { Registers::r6 }; +static const MOZ_CONSTEXPR Register r7 = { Registers::r7 }; +static const MOZ_CONSTEXPR Register r8 = { Registers::r8 }; +static const MOZ_CONSTEXPR Register r9 = { Registers::r9 }; +static const MOZ_CONSTEXPR Register r10 = { Registers::r10 }; +static const MOZ_CONSTEXPR Register r11 = { Registers::r11 }; +static const MOZ_CONSTEXPR Register r12 = { Registers::ip }; +static const MOZ_CONSTEXPR Register ip = { Registers::ip }; +static const MOZ_CONSTEXPR Register sp = { Registers::sp }; +static const MOZ_CONSTEXPR Register r14 = { Registers::lr }; +static const MOZ_CONSTEXPR Register lr = { Registers::lr }; +static const MOZ_CONSTEXPR Register pc = { Registers::pc }; -static const Register ScratchRegister = {Registers::ip}; +static const MOZ_CONSTEXPR Register ScratchRegister = {Registers::ip}; -static const Register OsrFrameReg = r3; -static const Register ArgumentsRectifierReg = r8; -static const Register CallTempReg0 = r5; -static const Register CallTempReg1 = r6; -static const Register CallTempReg2 = r7; -static const Register CallTempReg3 = r8; -static const Register CallTempReg4 = r0; -static const Register CallTempReg5 = r1; -static const Register CallTempReg6 = r2; +static const MOZ_CONSTEXPR Register OsrFrameReg = r3; +static const MOZ_CONSTEXPR Register ArgumentsRectifierReg = r8; +static const MOZ_CONSTEXPR Register CallTempReg0 = r5; +static const MOZ_CONSTEXPR Register CallTempReg1 = r6; +static const MOZ_CONSTEXPR Register CallTempReg2 = r7; +static const MOZ_CONSTEXPR Register CallTempReg3 = r8; +static const MOZ_CONSTEXPR Register CallTempReg4 = r0; +static const MOZ_CONSTEXPR Register CallTempReg5 = r1; +static const MOZ_CONSTEXPR Register CallTempReg6 = r2; -static const Register IntArgReg0 = r0; -static const Register IntArgReg1 = r1; -static const Register IntArgReg2 = r2; -static const Register IntArgReg3 = r3; -static const Register GlobalReg = r10; -static const Register HeapReg = r11; -static const Register CallTempNonArgRegs[] = { r5, r6, r7, r8 }; +static const MOZ_CONSTEXPR Register IntArgReg0 = r0; +static const MOZ_CONSTEXPR Register IntArgReg1 = r1; +static const MOZ_CONSTEXPR Register IntArgReg2 = r2; +static const MOZ_CONSTEXPR Register IntArgReg3 = r3; +static const MOZ_CONSTEXPR Register GlobalReg = r10; +static const MOZ_CONSTEXPR Register HeapReg = r11; +static const MOZ_CONSTEXPR Register CallTempNonArgRegs[] = { r5, r6, r7, r8 }; static const uint32_t NumCallTempNonArgRegs = mozilla::ArrayLength(CallTempNonArgRegs); class ABIArgGenerator @@ -87,37 +88,37 @@ class ABIArgGenerator }; -static const Register PreBarrierReg = r1; +static const MOZ_CONSTEXPR Register PreBarrierReg = r1; -static const Register InvalidReg = { Registers::invalid_reg }; -static const FloatRegister InvalidFloatReg = { FloatRegisters::invalid_freg }; +static const MOZ_CONSTEXPR Register InvalidReg = { Registers::invalid_reg }; +static const MOZ_CONSTEXPR FloatRegister InvalidFloatReg = { FloatRegisters::invalid_freg }; -static const Register JSReturnReg_Type = r3; -static const Register JSReturnReg_Data = r2; -static const Register StackPointer = sp; -static const Register FramePointer = InvalidReg; -static const Register ReturnReg = r0; -static const FloatRegister ReturnFloatReg = { FloatRegisters::d0 }; -static const FloatRegister ScratchFloatReg = { FloatRegisters::d1 }; +static const MOZ_CONSTEXPR Register JSReturnReg_Type = r3; +static const MOZ_CONSTEXPR Register JSReturnReg_Data = r2; +static const MOZ_CONSTEXPR Register StackPointer = sp; +static const MOZ_CONSTEXPR Register FramePointer = InvalidReg; +static const MOZ_CONSTEXPR Register ReturnReg = r0; +static const MOZ_CONSTEXPR FloatRegister ReturnFloatReg = { FloatRegisters::d0 }; +static const MOZ_CONSTEXPR FloatRegister ScratchFloatReg = { FloatRegisters::d1 }; -static const FloatRegister NANReg = { FloatRegisters::d15 }; +static const MOZ_CONSTEXPR FloatRegister NANReg = { FloatRegisters::d15 }; -static const FloatRegister d0 = {FloatRegisters::d0}; -static const FloatRegister d1 = {FloatRegisters::d1}; -static const FloatRegister d2 = {FloatRegisters::d2}; -static const FloatRegister d3 = {FloatRegisters::d3}; -static const FloatRegister d4 = {FloatRegisters::d4}; -static const FloatRegister d5 = {FloatRegisters::d5}; -static const FloatRegister d6 = {FloatRegisters::d6}; -static const FloatRegister d7 = {FloatRegisters::d7}; -static const FloatRegister d8 = {FloatRegisters::d8}; -static const FloatRegister d9 = {FloatRegisters::d9}; -static const FloatRegister d10 = {FloatRegisters::d10}; -static const FloatRegister d11 = {FloatRegisters::d11}; -static const FloatRegister d12 = {FloatRegisters::d12}; -static const FloatRegister d13 = {FloatRegisters::d13}; -static const FloatRegister d14 = {FloatRegisters::d14}; -static const FloatRegister d15 = {FloatRegisters::d15}; +static const MOZ_CONSTEXPR FloatRegister d0 = {FloatRegisters::d0}; +static const MOZ_CONSTEXPR FloatRegister d1 = {FloatRegisters::d1}; +static const MOZ_CONSTEXPR FloatRegister d2 = {FloatRegisters::d2}; +static const MOZ_CONSTEXPR FloatRegister d3 = {FloatRegisters::d3}; +static const MOZ_CONSTEXPR FloatRegister d4 = {FloatRegisters::d4}; +static const MOZ_CONSTEXPR FloatRegister d5 = {FloatRegisters::d5}; +static const MOZ_CONSTEXPR FloatRegister d6 = {FloatRegisters::d6}; +static const MOZ_CONSTEXPR FloatRegister d7 = {FloatRegisters::d7}; +static const MOZ_CONSTEXPR FloatRegister d8 = {FloatRegisters::d8}; +static const MOZ_CONSTEXPR FloatRegister d9 = {FloatRegisters::d9}; +static const MOZ_CONSTEXPR FloatRegister d10 = {FloatRegisters::d10}; +static const MOZ_CONSTEXPR FloatRegister d11 = {FloatRegisters::d11}; +static const MOZ_CONSTEXPR FloatRegister d12 = {FloatRegisters::d12}; +static const MOZ_CONSTEXPR FloatRegister d13 = {FloatRegisters::d13}; +static const MOZ_CONSTEXPR FloatRegister d14 = {FloatRegisters::d14}; +static const MOZ_CONSTEXPR FloatRegister d15 = {FloatRegisters::d15}; // For maximal awesomeness, 8 should be sufficent. // ldrd/strd (dual-register load/store) operate in a single cycle diff --git a/js/src/ion/x64/Assembler-x64.h b/js/src/ion/x64/Assembler-x64.h index 909327bca425..82874703737b 100644 --- a/js/src/ion/x64/Assembler-x64.h +++ b/js/src/ion/x64/Assembler-x64.h @@ -15,39 +15,39 @@ namespace js { namespace ion { -static const Register rax = { JSC::X86Registers::eax }; -static const Register rbx = { JSC::X86Registers::ebx }; -static const Register rcx = { JSC::X86Registers::ecx }; -static const Register rdx = { JSC::X86Registers::edx }; -static const Register rsi = { JSC::X86Registers::esi }; -static const Register rdi = { JSC::X86Registers::edi }; -static const Register rbp = { JSC::X86Registers::ebp }; -static const Register r8 = { JSC::X86Registers::r8 }; -static const Register r9 = { JSC::X86Registers::r9 }; -static const Register r10 = { JSC::X86Registers::r10 }; -static const Register r11 = { JSC::X86Registers::r11 }; -static const Register r12 = { JSC::X86Registers::r12 }; -static const Register r13 = { JSC::X86Registers::r13 }; -static const Register r14 = { JSC::X86Registers::r14 }; -static const Register r15 = { JSC::X86Registers::r15 }; -static const Register rsp = { JSC::X86Registers::esp }; +static const MOZ_CONSTEXPR Register rax = { JSC::X86Registers::eax }; +static const MOZ_CONSTEXPR Register rbx = { JSC::X86Registers::ebx }; +static const MOZ_CONSTEXPR Register rcx = { JSC::X86Registers::ecx }; +static const MOZ_CONSTEXPR Register rdx = { JSC::X86Registers::edx }; +static const MOZ_CONSTEXPR Register rsi = { JSC::X86Registers::esi }; +static const MOZ_CONSTEXPR Register rdi = { JSC::X86Registers::edi }; +static const MOZ_CONSTEXPR Register rbp = { JSC::X86Registers::ebp }; +static const MOZ_CONSTEXPR Register r8 = { JSC::X86Registers::r8 }; +static const MOZ_CONSTEXPR Register r9 = { JSC::X86Registers::r9 }; +static const MOZ_CONSTEXPR Register r10 = { JSC::X86Registers::r10 }; +static const MOZ_CONSTEXPR Register r11 = { JSC::X86Registers::r11 }; +static const MOZ_CONSTEXPR Register r12 = { JSC::X86Registers::r12 }; +static const MOZ_CONSTEXPR Register r13 = { JSC::X86Registers::r13 }; +static const MOZ_CONSTEXPR Register r14 = { JSC::X86Registers::r14 }; +static const MOZ_CONSTEXPR Register r15 = { JSC::X86Registers::r15 }; +static const MOZ_CONSTEXPR Register rsp = { JSC::X86Registers::esp }; -static const FloatRegister xmm0 = { JSC::X86Registers::xmm0 }; -static const FloatRegister xmm1 = { JSC::X86Registers::xmm1 }; -static const FloatRegister xmm2 = { JSC::X86Registers::xmm2 }; -static const FloatRegister xmm3 = { JSC::X86Registers::xmm3 }; -static const FloatRegister xmm4 = { JSC::X86Registers::xmm4 }; -static const FloatRegister xmm5 = { JSC::X86Registers::xmm5 }; -static const FloatRegister xmm6 = { JSC::X86Registers::xmm6 }; -static const FloatRegister xmm7 = { JSC::X86Registers::xmm7 }; -static const FloatRegister xmm8 = { JSC::X86Registers::xmm8 }; -static const FloatRegister xmm9 = { JSC::X86Registers::xmm9 }; -static const FloatRegister xmm10 = { JSC::X86Registers::xmm10 }; -static const FloatRegister xmm11 = { JSC::X86Registers::xmm11 }; -static const FloatRegister xmm12 = { JSC::X86Registers::xmm12 }; -static const FloatRegister xmm13 = { JSC::X86Registers::xmm13 }; -static const FloatRegister xmm14 = { JSC::X86Registers::xmm14 }; -static const FloatRegister xmm15 = { JSC::X86Registers::xmm15 }; +static const MOZ_CONSTEXPR FloatRegister xmm0 = { JSC::X86Registers::xmm0 }; +static const MOZ_CONSTEXPR FloatRegister xmm1 = { JSC::X86Registers::xmm1 }; +static const MOZ_CONSTEXPR FloatRegister xmm2 = { JSC::X86Registers::xmm2 }; +static const MOZ_CONSTEXPR FloatRegister xmm3 = { JSC::X86Registers::xmm3 }; +static const MOZ_CONSTEXPR FloatRegister xmm4 = { JSC::X86Registers::xmm4 }; +static const MOZ_CONSTEXPR FloatRegister xmm5 = { JSC::X86Registers::xmm5 }; +static const MOZ_CONSTEXPR FloatRegister xmm6 = { JSC::X86Registers::xmm6 }; +static const MOZ_CONSTEXPR FloatRegister xmm7 = { JSC::X86Registers::xmm7 }; +static const MOZ_CONSTEXPR FloatRegister xmm8 = { JSC::X86Registers::xmm8 }; +static const MOZ_CONSTEXPR FloatRegister xmm9 = { JSC::X86Registers::xmm9 }; +static const MOZ_CONSTEXPR FloatRegister xmm10 = { JSC::X86Registers::xmm10 }; +static const MOZ_CONSTEXPR FloatRegister xmm11 = { JSC::X86Registers::xmm11 }; +static const MOZ_CONSTEXPR FloatRegister xmm12 = { JSC::X86Registers::xmm12 }; +static const MOZ_CONSTEXPR FloatRegister xmm13 = { JSC::X86Registers::xmm13 }; +static const MOZ_CONSTEXPR FloatRegister xmm14 = { JSC::X86Registers::xmm14 }; +static const MOZ_CONSTEXPR FloatRegister xmm15 = { JSC::X86Registers::xmm15 }; // X86-common synonyms. static const Register eax = rax; @@ -59,74 +59,74 @@ static const Register edi = rdi; static const Register ebp = rbp; static const Register esp = rsp; -static const Register InvalidReg = { JSC::X86Registers::invalid_reg }; -static const FloatRegister InvalidFloatReg = { JSC::X86Registers::invalid_xmm }; +static const MOZ_CONSTEXPR Register InvalidReg = { JSC::X86Registers::invalid_reg }; +static const MOZ_CONSTEXPR FloatRegister InvalidFloatReg = { JSC::X86Registers::invalid_xmm }; static const Register StackPointer = rsp; static const Register FramePointer = rbp; -static const Register JSReturnReg = rcx; +static const MOZ_CONSTEXPR Register JSReturnReg = rcx; // Avoid, except for assertions. -static const Register JSReturnReg_Type = JSReturnReg; -static const Register JSReturnReg_Data = JSReturnReg; +static const MOZ_CONSTEXPR Register JSReturnReg_Type = JSReturnReg; +static const MOZ_CONSTEXPR Register JSReturnReg_Data = JSReturnReg; -static const Register ReturnReg = rax; -static const Register ScratchReg = r11; -static const Register HeapReg = r15; -static const FloatRegister ReturnFloatReg = xmm0; -static const FloatRegister ScratchFloatReg = xmm15; +static const MOZ_CONSTEXPR Register ReturnReg = rax; +static const MOZ_CONSTEXPR Register ScratchReg = r11; +static const MOZ_CONSTEXPR Register HeapReg = r15; +static const MOZ_CONSTEXPR FloatRegister ReturnFloatReg = xmm0; +static const MOZ_CONSTEXPR FloatRegister ScratchFloatReg = xmm15; -static const Register ArgumentsRectifierReg = r8; -static const Register CallTempReg0 = rax; -static const Register CallTempReg1 = rdi; -static const Register CallTempReg2 = rbx; -static const Register CallTempReg3 = rcx; -static const Register CallTempReg4 = rsi; -static const Register CallTempReg5 = rdx; -static const Register CallTempReg6 = rbp; +static const MOZ_CONSTEXPR Register ArgumentsRectifierReg = r8; +static const MOZ_CONSTEXPR Register CallTempReg0 = rax; +static const MOZ_CONSTEXPR Register CallTempReg1 = rdi; +static const MOZ_CONSTEXPR Register CallTempReg2 = rbx; +static const MOZ_CONSTEXPR Register CallTempReg3 = rcx; +static const MOZ_CONSTEXPR Register CallTempReg4 = rsi; +static const MOZ_CONSTEXPR Register CallTempReg5 = rdx; +static const MOZ_CONSTEXPR Register CallTempReg6 = rbp; // Different argument registers for WIN64 #if defined(_WIN64) -static const Register IntArgReg0 = rcx; -static const Register IntArgReg1 = rdx; -static const Register IntArgReg2 = r8; -static const Register IntArgReg3 = r9; -static const uint32_t NumIntArgRegs = 4; -static const Register IntArgRegs[NumIntArgRegs] = { rcx, rdx, r8, r9 }; +static const MOZ_CONSTEXPR Register IntArgReg0 = rcx; +static constMOZ_CONSTEXPRconstexpr Register IntArgReg1 = rdx; +static const MOZ_CONSTEXPR Register IntArgReg2 = r8; +static const MOZ_CONSTEXPR Register IntArgReg3 = r9; +static constMOZ_CONSTEXPRuint32_t NumIntArgRegs = 4; +static const MOZ_CONSTEXPR Register IntArgRegs[NumIntArgRegs] = { rcx, rdx, r8, r9 }; -static const Register CallTempNonArgRegs[] = { rax, rdi, rbx, rsi }; +static const MOZ_CONSTEXPR Register CallTempNonArgRegs[] = { rax, rdi, rbx, rsi }; static const uint32_t NumCallTempNonArgRegs = mozilla::ArrayLength(CallTempNonArgRegs); -static const FloatRegister FloatArgReg0 = xmm0; -static const FloatRegister FloatArgReg1 = xmm1; -static const FloatRegister FloatArgReg2 = xmm2; -static const FloatRegister FloatArgReg3 = xmm3; +static const MOZ_CONSTEXPR FloatRegister FloatArgReg0 = xmm0; +static const MOZ_CONSTEXPR FloatRegister FloatArgReg1 = xmm1; +static const MOZ_CONSTEXPR FloatRegister FloatArgReg2 = xmm2; +static const MOZ_CONSTEXPR FloatRegister FloatArgReg3 = xmm3; static const uint32_t NumFloatArgRegs = 4; static const FloatRegister FloatArgRegs[NumFloatArgRegs] = { xmm0, xmm1, xmm2, xmm3 }; #else -static const Register IntArgReg0 = rdi; -static const Register IntArgReg1 = rsi; -static const Register IntArgReg2 = rdx; -static const Register IntArgReg3 = rcx; -static const Register IntArgReg4 = r8; -static const Register IntArgReg5 = r9; -static const uint32_t NumIntArgRegs = 6; -static const Register IntArgRegs[NumIntArgRegs] = { rdi, rsi, rdx, rcx, r8, r9 }; +static const MOZ_CONSTEXPR Register IntArgReg0 = rdi; +static const MOZ_CONSTEXPR Register IntArgReg1 = rsi; +static const MOZ_CONSTEXPR Register IntArgReg2 = rdx; +static const MOZ_CONSTEXPR Register IntArgReg3 = rcx; +static const MOZ_CONSTEXPR Register IntArgReg4 = r8; +static const MOZ_CONSTEXPR Register IntArgReg5 = r9; +static const MOZ_CONSTEXPR uint32_t NumIntArgRegs = 6; +static const MOZ_CONSTEXPR Register IntArgRegs[NumIntArgRegs] = { rdi, rsi, rdx, rcx, r8, r9 }; -static const Register CallTempNonArgRegs[] = { rax, rbx }; +static const MOZ_CONSTEXPR Register CallTempNonArgRegs[] = { rax, rbx }; static const uint32_t NumCallTempNonArgRegs = mozilla::ArrayLength(CallTempNonArgRegs); -static const FloatRegister FloatArgReg0 = xmm0; -static const FloatRegister FloatArgReg1 = xmm1; -static const FloatRegister FloatArgReg2 = xmm2; -static const FloatRegister FloatArgReg3 = xmm3; -static const FloatRegister FloatArgReg4 = xmm4; -static const FloatRegister FloatArgReg5 = xmm5; -static const FloatRegister FloatArgReg6 = xmm6; -static const FloatRegister FloatArgReg7 = xmm7; -static const uint32_t NumFloatArgRegs = 8; -static const FloatRegister FloatArgRegs[NumFloatArgRegs] = { xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7 }; +static const MOZ_CONSTEXPR FloatRegister FloatArgReg0 = xmm0; +static const MOZ_CONSTEXPR FloatRegister FloatArgReg1 = xmm1; +static const MOZ_CONSTEXPR FloatRegister FloatArgReg2 = xmm2; +static const MOZ_CONSTEXPR FloatRegister FloatArgReg3 = xmm3; +static const MOZ_CONSTEXPR FloatRegister FloatArgReg4 = xmm4; +static const MOZ_CONSTEXPR FloatRegister FloatArgReg5 = xmm5; +static const MOZ_CONSTEXPR FloatRegister FloatArgReg6 = xmm6; +static const MOZ_CONSTEXPR FloatRegister FloatArgReg7 = xmm7; +static const MOZ_CONSTEXPR uint32_t NumFloatArgRegs = 8; +static const MOZ_CONSTEXPR FloatRegister FloatArgRegs[NumFloatArgRegs] = { xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7 }; #endif class ABIArgGenerator @@ -152,9 +152,9 @@ class ABIArgGenerator static const Register NonVolatileReg; }; -static const Register OsrFrameReg = IntArgReg3; +static const MOZ_CONSTEXPR Register OsrFrameReg = IntArgReg3; -static const Register PreBarrierReg = rdx; +static const MOZ_CONSTEXPR Register PreBarrierReg = rdx; // GCC stack is aligned on 16 bytes, but we don't maintain the invariant in // jitted code. @@ -265,7 +265,7 @@ namespace js { namespace ion { // Return operand from a JS -> JS call. -static const ValueOperand JSReturnOperand = ValueOperand(JSReturnReg); +static const MOZ_CONSTEXPR ValueOperand JSReturnOperand = ValueOperand(JSReturnReg); class Assembler : public AssemblerX86Shared { diff --git a/js/src/ion/x86/Assembler-x86.h b/js/src/ion/x86/Assembler-x86.h index 64cfcdccd80f..e9476db4a43e 100644 --- a/js/src/ion/x86/Assembler-x86.h +++ b/js/src/ion/x86/Assembler-x86.h @@ -18,46 +18,46 @@ namespace js { namespace ion { -static const Register eax = { JSC::X86Registers::eax }; -static const Register ecx = { JSC::X86Registers::ecx }; -static const Register edx = { JSC::X86Registers::edx }; -static const Register ebx = { JSC::X86Registers::ebx }; -static const Register esp = { JSC::X86Registers::esp }; -static const Register ebp = { JSC::X86Registers::ebp }; -static const Register esi = { JSC::X86Registers::esi }; -static const Register edi = { JSC::X86Registers::edi }; +static const MOZ_CONSTEXPR Register eax = { JSC::X86Registers::eax }; +static const MOZ_CONSTEXPR Register ecx = { JSC::X86Registers::ecx }; +static const MOZ_CONSTEXPR Register edx = { JSC::X86Registers::edx }; +static const MOZ_CONSTEXPR Register ebx = { JSC::X86Registers::ebx }; +static const MOZ_CONSTEXPR Register esp = { JSC::X86Registers::esp }; +static const MOZ_CONSTEXPR Register ebp = { JSC::X86Registers::ebp }; +static const MOZ_CONSTEXPR Register esi = { JSC::X86Registers::esi }; +static const MOZ_CONSTEXPR Register edi = { JSC::X86Registers::edi }; -static const FloatRegister xmm0 = { JSC::X86Registers::xmm0 }; -static const FloatRegister xmm1 = { JSC::X86Registers::xmm1 }; -static const FloatRegister xmm2 = { JSC::X86Registers::xmm2 }; -static const FloatRegister xmm3 = { JSC::X86Registers::xmm3 }; -static const FloatRegister xmm4 = { JSC::X86Registers::xmm4 }; -static const FloatRegister xmm5 = { JSC::X86Registers::xmm5 }; -static const FloatRegister xmm6 = { JSC::X86Registers::xmm6 }; -static const FloatRegister xmm7 = { JSC::X86Registers::xmm7 }; +static const MOZ_CONSTEXPR FloatRegister xmm0 = { JSC::X86Registers::xmm0 }; +static const MOZ_CONSTEXPR FloatRegister xmm1 = { JSC::X86Registers::xmm1 }; +static const MOZ_CONSTEXPR FloatRegister xmm2 = { JSC::X86Registers::xmm2 }; +static const MOZ_CONSTEXPR FloatRegister xmm3 = { JSC::X86Registers::xmm3 }; +static const MOZ_CONSTEXPR FloatRegister xmm4 = { JSC::X86Registers::xmm4 }; +static const MOZ_CONSTEXPR FloatRegister xmm5 = { JSC::X86Registers::xmm5 }; +static const MOZ_CONSTEXPR FloatRegister xmm6 = { JSC::X86Registers::xmm6 }; +static const MOZ_CONSTEXPR FloatRegister xmm7 = { JSC::X86Registers::xmm7 }; -static const Register InvalidReg = { JSC::X86Registers::invalid_reg }; -static const FloatRegister InvalidFloatReg = { JSC::X86Registers::invalid_xmm }; +static const MOZ_CONSTEXPR Register InvalidReg = { JSC::X86Registers::invalid_reg }; +static const MOZ_CONSTEXPR FloatRegister InvalidFloatReg = { JSC::X86Registers::invalid_xmm }; -static const Register JSReturnReg_Type = ecx; -static const Register JSReturnReg_Data = edx; -static const Register StackPointer = esp; -static const Register FramePointer = ebp; -static const Register ReturnReg = eax; -static const FloatRegister ReturnFloatReg = xmm0; -static const FloatRegister ScratchFloatReg = xmm7; +static const MOZ_CONSTEXPR Register JSReturnReg_Type = ecx; +static const MOZ_CONSTEXPR Register JSReturnReg_Data = edx; +static const MOZ_CONSTEXPR Register StackPointer = esp; +static const MOZ_CONSTEXPR Register FramePointer = ebp; +static const MOZ_CONSTEXPR Register ReturnReg = eax; +static const MOZ_CONSTEXPR FloatRegister ReturnFloatReg = xmm0; +static const MOZ_CONSTEXPR FloatRegister ScratchFloatReg = xmm7; -static const Register ArgumentsRectifierReg = esi; -static const Register CallTempReg0 = edi; -static const Register CallTempReg1 = eax; -static const Register CallTempReg2 = ebx; -static const Register CallTempReg3 = ecx; -static const Register CallTempReg4 = esi; -static const Register CallTempReg5 = edx; -static const Register CallTempReg6 = ebp; +static const MOZ_CONSTEXPR Register ArgumentsRectifierReg = esi; +static const MOZ_CONSTEXPR Register CallTempReg0 = edi; +static const MOZ_CONSTEXPR Register CallTempReg1 = eax; +static const MOZ_CONSTEXPR Register CallTempReg2 = ebx; +static const MOZ_CONSTEXPR Register CallTempReg3 = ecx; +static const MOZ_CONSTEXPR Register CallTempReg4 = esi; +static const MOZ_CONSTEXPR Register CallTempReg5 = edx; +static const MOZ_CONSTEXPR Register CallTempReg6 = ebp; // We have no arg regs, so our NonArgRegs are just our CallTempReg* -static const Register CallTempNonArgRegs[] = { edi, eax, ebx, ecx, esi, edx }; +static const MOZ_CONSTEXPR Register CallTempNonArgRegs[] = { edi, eax, ebx, ecx, esi, edx }; static const uint32_t NumCallTempNonArgRegs = mozilla::ArrayLength(CallTempNonArgRegs); @@ -78,8 +78,8 @@ class ABIArgGenerator static const Register NonVolatileReg; }; -static const Register OsrFrameReg = edx; -static const Register PreBarrierReg = edx; +static const MOZ_CONSTEXPR Register OsrFrameReg = edx; +static const MOZ_CONSTEXPR Register PreBarrierReg = edx; // GCC stack is aligned on 16 bytes, but we don't maintain the invariant in // jitted code. From 1ca578aba79a71b9a70ddc56c05f496946d47098 Mon Sep 17 00:00:00 2001 From: Trevor Saunders Date: Wed, 12 Jun 2013 05:13:34 -0400 Subject: [PATCH 40/84] bug 852129 - use HyperTextAccessible for invalid img r=surkov, bz If the img is not valid then its children will be rendered, and the sensible way to handle that is by giving the img a HyperTextAccessible instead of an ImageAccessible. Since the accessible name of such an img should be the value of the alt attribute we add similar logic as ImageAccessible::NativeName() to HyperTextAccessible::NativeName() conditioned on the tag being img. --- .../src/generic/HyperTextAccessible.cpp | 10 +++- .../tests/mochitest/name/test_general.html | 2 + accessible/tests/mochitest/tree/Makefile.in | 1 + .../mochitest/tree/test_invalid_img.xhtml | 50 +++++++++++++++++++ layout/generic/nsInlineFrame.cpp | 2 +- 5 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 accessible/tests/mochitest/tree/test_invalid_img.xhtml diff --git a/accessible/src/generic/HyperTextAccessible.cpp b/accessible/src/generic/HyperTextAccessible.cpp index 94d55192526e..28b0c91dd652 100644 --- a/accessible/src/generic/HyperTextAccessible.cpp +++ b/accessible/src/generic/HyperTextAccessible.cpp @@ -2112,6 +2112,14 @@ HyperTextAccessible::ScrollSubstringToPoint(int32_t aStartIndex, ENameValueFlag HyperTextAccessible::NativeName(nsString& aName) { + // Check @alt attribute for invalid img elements. + bool hasImgAlt = false; + if (mContent->IsHTML(nsGkAtoms::img)) { + hasImgAlt = mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aName); + if (!aName.IsEmpty()) + return eNameOK; + } + ENameValueFlag nameFlag = AccessibleWrap::NativeName(aName); if (!aName.IsEmpty()) return nameFlag; @@ -2123,7 +2131,7 @@ HyperTextAccessible::NativeName(nsString& aName) mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aName)) aName.CompressWhitespace(); - return eNameOK; + return hasImgAlt ? eNoNameOnPurpose : eNameOK; } void diff --git a/accessible/tests/mochitest/name/test_general.html b/accessible/tests/mochitest/name/test_general.html index d28626ae3214..737e523bb6b7 100644 --- a/accessible/tests/mochitest/name/test_general.html +++ b/accessible/tests/mochitest/name/test_general.html @@ -208,6 +208,7 @@ // Test equation image testName("img_eq", "x^2 + y^2 + z^2") + testName("input_img_eq", "x^2 + y^2 + z^2") testName("txt_eq", "x^2 + y^2 + z^2") //////////////////////////////////////////////////////////////////////// @@ -606,6 +607,7 @@

Image: x^2 + y^2 + z^2 +

Text: diff --git a/accessible/tests/mochitest/tree/Makefile.in b/accessible/tests/mochitest/tree/Makefile.in index 9631b3db8f94..900615a966d2 100644 --- a/accessible/tests/mochitest/tree/Makefile.in +++ b/accessible/tests/mochitest/tree/Makefile.in @@ -34,6 +34,7 @@ MOCHITEST_A11Y_FILES =\ test_groupbox.xul \ test_iframe.html \ test_img.html \ + test_invalid_img.xhtml \ test_invalidationlist.html \ test_list.html \ test_map.html \ diff --git a/accessible/tests/mochitest/tree/test_invalid_img.xhtml b/accessible/tests/mochitest/tree/test_invalid_img.xhtml new file mode 100644 index 000000000000..14ada63224ea --- /dev/null +++ b/accessible/tests/mochitest/tree/test_invalid_img.xhtml @@ -0,0 +1,50 @@ + + + invalid html img + + + + + + + + + + + + + + Mozilla Bug 852129 + + +

+ +
+  
+ + 1 + + diff --git a/layout/generic/nsInlineFrame.cpp b/layout/generic/nsInlineFrame.cpp index c6f905d9e0b5..755478efe1a1 100644 --- a/layout/generic/nsInlineFrame.cpp +++ b/layout/generic/nsInlineFrame.cpp @@ -918,7 +918,7 @@ nsInlineFrame::AccessibleType() if (tagAtom == nsGkAtoms::input) // Broken return a11y::eHTMLButtonType; if (tagAtom == nsGkAtoms::img) // Create accessible for broken - return a11y::eImageType; + return a11y::eHyperTextType; if (tagAtom == nsGkAtoms::label) // Creat accessible for